From 298d50b61e33f2f724e30d7026936c0df6804e02 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Tue, 29 Jan 2013 14:38:01 -0500 Subject: [PATCH 01/80] changing the space invisible to 00b7 'middot' --- src/app/editor.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/editor.coffee b/src/app/editor.coffee index d4a1a4093..d0041c1bd 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -312,7 +312,7 @@ class Editor extends View setInvisibles: (@invisibles={}) -> _.defaults @invisibles, eol: '\u00ac' - space: '\u2022' + space: '\u00b7' tab: '\u00bb' cr: '\u00a4' @resetDisplay() From ad7e4b63c00eca7478b24222b415e55258945f2e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 29 Jan 2013 08:36:24 -0800 Subject: [PATCH 02/80] Bind ctrl-meta-up to move line(s) up Refs #134 --- spec/app/editor-spec.coffee | 90 +++++++++++++++++++++++++++++++++++++ src/app/edit-session.coffee | 33 ++++++++++++++ src/app/editor.coffee | 2 + src/app/keymaps/editor.cson | 1 + src/app/line-map.coffee | 2 +- src/app/point.coffee | 6 +++ 6 files changed, 133 insertions(+), 1 deletion(-) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index 25dc557dc..06e0b95b5 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -2260,3 +2260,93 @@ describe "Editor", -> it "copies the absolute path to the editor's file to the pasteboard", -> editor.trigger 'editor:copy-path' expect(pasteboard.read()[0]).toBe editor.getPath() + + describe "when editor:move-line-up is triggered", -> + describe "when there is no selection", -> + it "moves the line where the cursor is up", -> + editor.setCursorBufferPosition([1,0]) + editor.trigger 'editor:move-line-up' + expect(buffer.lineForRow(0)).toBe ' var sort = function(items) {' + expect(buffer.lineForRow(1)).toBe 'var quicksort = function () {' + + it "moves the cursor to the new row and the same column", -> + editor.setCursorBufferPosition([1,2]) + editor.trigger 'editor:move-line-up' + expect(editor.getCursorBufferPosition()).toEqual [0,2] + + describe "where there is a selection", -> + describe "when the selection falls inside the line", -> + it "maintains the selection", -> + editor.setSelectedBufferRange([[1, 2], [1, 5]]) + expect(editor.getSelectedText()).toBe 'var' + editor.trigger 'editor:move-line-up' + expect(editor.getSelectedBufferRange()).toEqual [[0, 2], [0, 5]] + expect(editor.getSelectedText()).toBe 'var' + + describe "where there are multiple lines selected", -> + it "moves the selected lines up", -> + editor.setSelectedBufferRange([[2, 0], [3, Infinity]]) + editor.trigger 'editor:move-line-up' + expect(buffer.lineForRow(0)).toBe 'var quicksort = function () {' + expect(buffer.lineForRow(1)).toBe ' if (items.length <= 1) return items;' + expect(buffer.lineForRow(2)).toBe ' var pivot = items.shift(), current, left = [], right = [];' + expect(buffer.lineForRow(3)).toBe ' var sort = function(items) {' + + it "maintains the selection", -> + editor.setSelectedBufferRange([[2, 0], [3, 62]]) + editor.trigger 'editor:move-line-up' + expect(editor.getSelectedBufferRange()).toEqual [[1, 0], [2, 62]] + + describe "when the last line is selected", -> + it "moves the selected line up", -> + editor.setSelectedBufferRange([[12, 0], [12, Infinity]]) + editor.trigger 'editor:move-line-up' + expect(buffer.lineForRow(11)).toBe '};' + expect(buffer.lineForRow(12)).toBe ' return sort(Array.apply(this, arguments));' + + describe "when the last two lines are selected", -> + it "moves the selected lines up", -> + editor.setSelectedBufferRange([[11, 0], [12, Infinity]]) + editor.trigger 'editor:move-line-up' + expect(buffer.lineForRow(10)).toBe ' return sort(Array.apply(this, arguments));' + expect(buffer.lineForRow(11)).toBe '};' + expect(buffer.lineForRow(12)).toBe '' + + describe "when the cursor is on the first line", -> + it "does not move the line", -> + editor.setCursorBufferPosition([0,0]) + originalText = editor.getText() + editor.trigger 'editor:move-line-up' + expect(editor.getText()).toBe originalText + + describe "when the cursor is on the trailing newline", -> + it "does not move the line", -> + editor.moveCursorToBottom() + editor.insertNewline() + editor.moveCursorToBottom() + originalText = editor.getText() + editor.trigger 'editor:move-line-up' + expect(editor.getText()).toBe originalText + + describe "when the cursor is on a folded line", -> + it "moves all lines in the fold up and preserves the fold", -> + editor.setCursorBufferPosition([4, 0]) + editor.foldCurrentRow() + editor.trigger 'editor:move-line-up' + expect(buffer.lineForRow(3)).toBe ' while(items.length > 0) {' + expect(buffer.lineForRow(7)).toBe ' var pivot = items.shift(), current, left = [], right = [];' + expect(editor.getSelectedBufferRange()).toEqual [[3, 0], [3, 0]] + expect(editor.isFoldedAtScreenRow(3)).toBeTruthy() + + describe "when a fold is selected", -> + it "moves the selected lines up and preserves the fold", -> + editor.setCursorBufferPosition([4, 0]) + editor.foldCurrentRow() + editor.setCursorBufferPosition([3, 4]) + editor.selectDown() + expect(editor.isFoldedAtScreenRow(4)).toBeTruthy() + editor.trigger 'editor:move-line-up' + expect(buffer.lineForRow(2)).toBe ' var pivot = items.shift(), current, left = [], right = [];' + expect(buffer.lineForRow(3)).toBe ' while(items.length > 0) {' + expect(editor.getSelectedBufferRange()).toEqual [[2, 4], [3,0]] + expect(editor.isFoldedAtScreenRow(3)).toBeTruthy() diff --git a/src/app/edit-session.coffee b/src/app/edit-session.coffee index 74fe4a2a3..fcedbd28f 100644 --- a/src/app/edit-session.coffee +++ b/src/app/edit-session.coffee @@ -334,6 +334,39 @@ class EditSession toggleLineCommentsForBufferRows: (start, end) -> @languageMode.toggleLineCommentsForBufferRows(start, end) + moveLineUp: -> + selection = @getSelectedBufferRange() + return if selection.start.row is 0 + lastRow = @buffer.getLastRow() + return if selection.isEmpty() and selection.start.row is lastRow and @buffer.getLastLine() is '' + + @transact => + for row in [selection.start.row..selection.end.row] + screenPosition = @screenPositionForBufferPosition([row, 0]) + isRowFolded = @isFoldedAtScreenRow(screenPosition.row) + if isRowFolded + bufferRange = @bufferRangeForScreenRange([[screenPosition.row, 0], [screenPosition.row + 1, 0]]) + startRow = bufferRange.start.row + endRow = bufferRange.end.row - 1 + else + startRow = row + endRow = row + + endPosition = Point.min([endRow + 1, 0], @buffer.getEofPosition()) + lines = @buffer.getTextInRange([[startRow, 0], endPosition]) + if endPosition.row is lastRow and endPosition.column > 0 and not @buffer.lineEndingForRow(endPosition.row) + lines = "#{lines}\n" + @buffer.deleteRows(startRow, endRow) + @buffer.insert([startRow - 1, 0], lines) + @foldBufferRow(startRow - 1) if isRowFolded + + newStartPosition = [selection.start.row - 1, selection.start.column] + if selection.isEmpty() + @setCursorBufferPosition(newStartPosition) + else + newEndPosition = [selection.end.row - 1, selection.end.column] + @setSelectedBufferRange([newStartPosition, newEndPosition], preserveFolds: true) + mutateSelectedText: (fn) -> @transact => fn(selection) for selection in @getSelections() diff --git a/src/app/editor.coffee b/src/app/editor.coffee index d0041c1bd..2afa97e4d 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -183,6 +183,7 @@ class Editor extends View 'editor:close-all-edit-sessions': @destroyAllEditSessions 'editor:select-grammar': @selectGrammar 'editor:copy-path': @copyPathToPasteboard + 'editor:move-line-up': @moveLineUp documentation = {} for name, method of editorBindings @@ -204,6 +205,7 @@ class Editor extends View moveCursorToBeginningOfLine: -> @activeEditSession.moveCursorToBeginningOfLine() moveCursorToFirstCharacterOfLine: -> @activeEditSession.moveCursorToFirstCharacterOfLine() moveCursorToEndOfLine: -> @activeEditSession.moveCursorToEndOfLine() + moveLineUp: -> @activeEditSession.moveLineUp() setCursorScreenPosition: (position) -> @activeEditSession.setCursorScreenPosition(position) getCursorScreenPosition: -> @activeEditSession.getCursorScreenPosition() getCursorScreenRow: -> @activeEditSession.getCursorScreenRow() diff --git a/src/app/keymaps/editor.cson b/src/app/keymaps/editor.cson index 06f0dd571..4cb724be2 100644 --- a/src/app/keymaps/editor.cson +++ b/src/app/keymaps/editor.cson @@ -38,3 +38,4 @@ 'meta-P': 'editor:close-all-edit-sessions' 'meta-L': 'editor:select-grammar' 'ctrl-C': 'editor:copy-path' + 'ctrl-meta-up': 'editor:move-line-up' diff --git a/src/app/line-map.coffee b/src/app/line-map.coffee index eae630887..1a5a74147 100644 --- a/src/app/line-map.coffee +++ b/src/app/line-map.coffee @@ -133,6 +133,7 @@ class LineMap new Range(start, end) bufferRangeForScreenRange: (screenRange) -> + screenRange = Range.fromObject(screenRange) start = @bufferPositionForScreenPosition(screenRange.start) end = @bufferPositionForScreenPosition(screenRange.end) new Range(start, end) @@ -141,4 +142,3 @@ class LineMap for row in [start..end] line = @lineForScreenRow(row).text console.log row, line, line.length - diff --git a/src/app/point.coffee b/src/app/point.coffee index a216cad0b..0b07e3ed7 100644 --- a/src/app/point.coffee +++ b/src/app/point.coffee @@ -11,6 +11,12 @@ class Point new Point(row, column) + @min: (point1, point2) -> + if @fromObject(point1).isLessThanOrEqual(@fromObject(point2)) + point1 + else + point2 + constructor: (@row=0, @column=0) -> copy: -> From 66df8603292edff2efa2cfe4ab556d83d700716b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 29 Jan 2013 14:37:55 -0800 Subject: [PATCH 03/80] :lipstick: --- src/app/buffer.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/buffer.coffee b/src/app/buffer.coffee index 266b30ba2..95d0819b1 100644 --- a/src/app/buffer.coffee +++ b/src/app/buffer.coffee @@ -117,7 +117,7 @@ class Buffer getTextInRange: (range) -> range = Range.fromObject(range) if range.start.row == range.end.row - return @lines[range.start.row][range.start.column...range.end.column] + return @lineForRow(range.start.row)[range.start.column...range.end.column] multipleLines = [] multipleLines.push @lineForRow(range.start.row)[range.start.column..] # first line From 348a0a3d9aed4074e0dab347a135f0e36ee14146 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 29 Jan 2013 14:38:28 -0800 Subject: [PATCH 04/80] Return normalized point --- src/app/point.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/point.coffee b/src/app/point.coffee index 0b07e3ed7..b740027f6 100644 --- a/src/app/point.coffee +++ b/src/app/point.coffee @@ -12,7 +12,9 @@ class Point new Point(row, column) @min: (point1, point2) -> - if @fromObject(point1).isLessThanOrEqual(@fromObject(point2)) + point1 = @fromObject(point1) + point2 = @fromObject(point2) + if point1.isLessThanOrEqual(point2) point1 else point2 From 096566ab2ac51698954a5d41ae4a25b5d7662070 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 29 Jan 2013 14:55:55 -0800 Subject: [PATCH 05/80] Bind ctrl-meta-down to move line(s) down Refs #134 --- spec/app/editor-spec.coffee | 89 ++++++++++++++++++++++++++++++++++++- src/app/edit-session.coffee | 58 ++++++++++++++++++++---- src/app/editor.coffee | 2 + src/app/keymaps/editor.cson | 1 + 4 files changed, 140 insertions(+), 10 deletions(-) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index 06e0b95b5..b6dcab74f 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -2338,7 +2338,7 @@ describe "Editor", -> expect(editor.getSelectedBufferRange()).toEqual [[3, 0], [3, 0]] expect(editor.isFoldedAtScreenRow(3)).toBeTruthy() - describe "when a fold is selected", -> + describe "when the selection contains a folded and unfolded line", -> it "moves the selected lines up and preserves the fold", -> editor.setCursorBufferPosition([4, 0]) editor.foldCurrentRow() @@ -2348,5 +2348,90 @@ describe "Editor", -> editor.trigger 'editor:move-line-up' expect(buffer.lineForRow(2)).toBe ' var pivot = items.shift(), current, left = [], right = [];' expect(buffer.lineForRow(3)).toBe ' while(items.length > 0) {' - expect(editor.getSelectedBufferRange()).toEqual [[2, 4], [3,0]] + expect(editor.getSelectedBufferRange()).toEqual [[2, 4], [3, 0]] expect(editor.isFoldedAtScreenRow(3)).toBeTruthy() + + describe "when editor:move-line-down is triggered", -> + describe "when there is no selection", -> + it "moves the line where the cursor is down", -> + editor.setCursorBufferPosition([0, 0]) + editor.trigger 'editor:move-line-down' + expect(buffer.lineForRow(0)).toBe ' var sort = function(items) {' + expect(buffer.lineForRow(1)).toBe 'var quicksort = function () {' + + it "moves the cursor to the new row and the same column", -> + editor.setCursorBufferPosition([0, 2]) + editor.trigger 'editor:move-line-down' + expect(editor.getCursorBufferPosition()).toEqual [1, 2] + + describe "when the cursor is on the last line", -> + it "does not move the line", -> + editor.moveCursorToBottom() + editor.trigger 'editor:move-line-down' + expect(buffer.lineForRow(12)).toBe '};' + expect(editor.getSelectedBufferRange()).toEqual [[12, 2], [12, 2]] + + describe "when the cursor is on the second to last line", -> + it "moves the line down", -> + editor.setCursorBufferPosition([11, 0]) + editor.trigger 'editor:move-line-down' + expect(buffer.lineForRow(11)).toBe '};' + expect(buffer.lineForRow(12)).toBe ' return sort(Array.apply(this, arguments));' + expect(buffer.lineForRow(13)).toBeUndefined() + + describe "when the cursor is on the second to last line and the last line is empty", -> + it "does not move the line", -> + editor.moveCursorToBottom() + editor.insertNewline() + editor.setCursorBufferPosition([12, 2]) + editor.trigger 'editor:move-line-down' + expect(buffer.lineForRow(12)).toBe '};' + expect(buffer.lineForRow(13)).toBe '' + expect(editor.getSelectedBufferRange()).toEqual [[12, 2], [12, 2]] + + describe "where there is a selection", -> + describe "when the selection falls inside the line", -> + it "maintains the selection", -> + editor.setSelectedBufferRange([[1, 2], [1, 5]]) + expect(editor.getSelectedText()).toBe 'var' + editor.trigger 'editor:move-line-down' + expect(editor.getSelectedBufferRange()).toEqual [[2, 2], [2, 5]] + expect(editor.getSelectedText()).toBe 'var' + + describe "where there are multiple lines selected", -> + it "moves the selected lines down", -> + editor.setSelectedBufferRange([[2, 0], [3, Infinity]]) + editor.trigger 'editor:move-line-down' + expect(buffer.lineForRow(2)).toBe ' while(items.length > 0) {' + expect(buffer.lineForRow(3)).toBe ' if (items.length <= 1) return items;' + expect(buffer.lineForRow(4)).toBe ' var pivot = items.shift(), current, left = [], right = [];' + expect(buffer.lineForRow(5)).toBe ' current = items.shift();' + + it "maintains the selection", -> + editor.setSelectedBufferRange([[2, 0], [3, 62]]) + editor.trigger 'editor:move-line-down' + expect(editor.getSelectedBufferRange()).toEqual [[3, 0], [4, 62]] + + describe "when the cursor is on a folded line", -> + it "moves all lines in the fold down and preserves the fold", -> + editor.setCursorBufferPosition([4, 0]) + editor.foldCurrentRow() + editor.trigger 'editor:move-line-down' + expect(buffer.lineForRow(4)).toBe ' return sort(left).concat(pivot).concat(sort(right));' + expect(buffer.lineForRow(5)).toBe ' while(items.length > 0) {' + expect(editor.getSelectedBufferRange()).toEqual [[5, 0], [5, 0]] + expect(editor.isFoldedAtScreenRow(5)).toBeTruthy() + + describe "when the selection contains a folded and unfolded line", -> + it "moves the selected lines down and preserves the fold", -> + editor.setCursorBufferPosition([4, 0]) + editor.foldCurrentRow() + editor.setCursorBufferPosition([3, 4]) + editor.selectDown() + expect(editor.isFoldedAtScreenRow(4)).toBeTruthy() + editor.trigger 'editor:move-line-down' + expect(buffer.lineForRow(3)).toBe ' return sort(left).concat(pivot).concat(sort(right));' + expect(buffer.lineForRow(4)).toBe ' var pivot = items.shift(), current, left = [], right = [];' + expect(buffer.lineForRow(5)).toBe ' while(items.length > 0) {' + expect(editor.getSelectedBufferRange()).toEqual [[4, 4], [5, 0]] + expect(editor.isFoldedAtScreenRow(5)).toBeTruthy() diff --git a/src/app/edit-session.coffee b/src/app/edit-session.coffee index fcedbd28f..52c319015 100644 --- a/src/app/edit-session.coffee +++ b/src/app/edit-session.coffee @@ -341,24 +341,26 @@ class EditSession return if selection.isEmpty() and selection.start.row is lastRow and @buffer.getLastLine() is '' @transact => + foldedRows = [] for row in [selection.start.row..selection.end.row] - screenPosition = @screenPositionForBufferPosition([row, 0]) - isRowFolded = @isFoldedAtScreenRow(screenPosition.row) - if isRowFolded - bufferRange = @bufferRangeForScreenRange([[screenPosition.row, 0], [screenPosition.row + 1, 0]]) + screenRow = @screenPositionForBufferPosition([row]).row + if @isFoldedAtScreenRow(screenRow) + bufferRange = @bufferRangeForScreenRange([[screenRow], [screenRow + 1]]) startRow = bufferRange.start.row endRow = bufferRange.end.row - 1 + foldedRows.push(endRow - 1) else startRow = row endRow = row - endPosition = Point.min([endRow + 1, 0], @buffer.getEofPosition()) - lines = @buffer.getTextInRange([[startRow, 0], endPosition]) + endPosition = Point.min([endRow + 1], @buffer.getEofPosition()) + lines = @buffer.getTextInRange([[startRow], endPosition]) if endPosition.row is lastRow and endPosition.column > 0 and not @buffer.lineEndingForRow(endPosition.row) lines = "#{lines}\n" @buffer.deleteRows(startRow, endRow) - @buffer.insert([startRow - 1, 0], lines) - @foldBufferRow(startRow - 1) if isRowFolded + @buffer.insert([startRow - 1], lines) + + @foldBufferRow(foldedRow) for foldedRow in foldedRows newStartPosition = [selection.start.row - 1, selection.start.column] if selection.isEmpty() @@ -367,6 +369,46 @@ class EditSession newEndPosition = [selection.end.row - 1, selection.end.column] @setSelectedBufferRange([newStartPosition, newEndPosition], preserveFolds: true) + moveLineDown: -> + selection = @getSelectedBufferRange() + lastRow = @buffer.getLastRow() + return if selection.end.row is lastRow + return if selection.end.row is lastRow - 1 and @buffer.getLastLine() is '' + + @transact => + foldedRows = [] + for row in [selection.end.row..selection.start.row] + screenRow = @screenPositionForBufferPosition([row]).row + if @isFoldedAtScreenRow(screenRow) + bufferRange = @bufferRangeForScreenRange([[screenRow], [screenRow + 1]]) + startRow = bufferRange.start.row + endRow = bufferRange.end.row - 1 + foldedRows.push(endRow + 1) + else + startRow = row + endRow = row + + if endRow + 1 is lastRow + endPosition = [endRow, @buffer.lineLengthForRow(endRow)] + else + endPosition = [endRow + 1] + lines = @buffer.getTextInRange([[startRow], endPosition]) + @buffer.deleteRows(startRow, endRow) + insertPosition = Point.min([startRow + 1], @buffer.getEofPosition()) + if insertPosition.row is @buffer.getLastRow() and insertPosition.column > 0 + lines = "\n#{lines}" + @buffer.insert(insertPosition, lines) + + @foldBufferRow(foldedRow) for foldedRow in foldedRows + + newStartPosition = [selection.start.row + 1, selection.start.column] + if selection.isEmpty() + @setCursorBufferPosition(newStartPosition) + else + newEndPosition = [selection.end.row + 1, selection.end.column] + @setSelectedBufferRange([newStartPosition, newEndPosition], preserveFolds: true) + + mutateSelectedText: (fn) -> @transact => fn(selection) for selection in @getSelections() diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 2afa97e4d..0fb628d4d 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -184,6 +184,7 @@ class Editor extends View 'editor:select-grammar': @selectGrammar 'editor:copy-path': @copyPathToPasteboard 'editor:move-line-up': @moveLineUp + 'editor:move-line-down': @moveLineDown documentation = {} for name, method of editorBindings @@ -206,6 +207,7 @@ class Editor extends View moveCursorToFirstCharacterOfLine: -> @activeEditSession.moveCursorToFirstCharacterOfLine() moveCursorToEndOfLine: -> @activeEditSession.moveCursorToEndOfLine() moveLineUp: -> @activeEditSession.moveLineUp() + moveLineDown: -> @activeEditSession.moveLineDown() setCursorScreenPosition: (position) -> @activeEditSession.setCursorScreenPosition(position) getCursorScreenPosition: -> @activeEditSession.getCursorScreenPosition() getCursorScreenRow: -> @activeEditSession.getCursorScreenRow() diff --git a/src/app/keymaps/editor.cson b/src/app/keymaps/editor.cson index 4cb724be2..4c977b698 100644 --- a/src/app/keymaps/editor.cson +++ b/src/app/keymaps/editor.cson @@ -39,3 +39,4 @@ 'meta-L': 'editor:select-grammar' 'ctrl-C': 'editor:copy-path' 'ctrl-meta-up': 'editor:move-line-up' + 'ctrl-meta-down': 'editor:move-line-down' From 367927faa136f5b863e4d341e4357a8c28108819 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 29 Jan 2013 15:08:21 -0800 Subject: [PATCH 06/80] Remove unneeded empty selection logic --- src/app/edit-session.coffee | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/app/edit-session.coffee b/src/app/edit-session.coffee index 52c319015..fbac2d16f 100644 --- a/src/app/edit-session.coffee +++ b/src/app/edit-session.coffee @@ -363,11 +363,8 @@ class EditSession @foldBufferRow(foldedRow) for foldedRow in foldedRows newStartPosition = [selection.start.row - 1, selection.start.column] - if selection.isEmpty() - @setCursorBufferPosition(newStartPosition) - else - newEndPosition = [selection.end.row - 1, selection.end.column] - @setSelectedBufferRange([newStartPosition, newEndPosition], preserveFolds: true) + newEndPosition = [selection.end.row - 1, selection.end.column] + @setSelectedBufferRange([newStartPosition, newEndPosition], preserveFolds: true) moveLineDown: -> selection = @getSelectedBufferRange() @@ -402,11 +399,8 @@ class EditSession @foldBufferRow(foldedRow) for foldedRow in foldedRows newStartPosition = [selection.start.row + 1, selection.start.column] - if selection.isEmpty() - @setCursorBufferPosition(newStartPosition) - else - newEndPosition = [selection.end.row + 1, selection.end.column] - @setSelectedBufferRange([newStartPosition, newEndPosition], preserveFolds: true) + newEndPosition = [selection.end.row + 1, selection.end.column] + @setSelectedBufferRange([newStartPosition, newEndPosition], preserveFolds: true) mutateSelectedText: (fn) -> From 1a04fa31d15a33563230a2fda3cdc01635fd7ac0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 29 Jan 2013 15:34:41 -0800 Subject: [PATCH 07/80] Clip range specified to Buffer.getTextInRange() --- spec/app/buffer-spec.coffee | 8 ++++++++ src/app/buffer.coffee | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/spec/app/buffer-spec.coffee b/spec/app/buffer-spec.coffee index ea10907cf..b13c2b7c2 100644 --- a/spec/app/buffer-spec.coffee +++ b/spec/app/buffer-spec.coffee @@ -465,6 +465,14 @@ describe 'Buffer', -> range = [[2,10], [4,10]] expect(buffer.getTextInRange(range)).toBe "ems.length <= 1) return items;\n var pivot = items.shift(), current, left = [], right = [];\n while(" + describe "when the range starts before the start of the buffer", -> + it "clips the range to the start of the buffer", -> + expect(buffer.getTextInRange([[-Infinity, -Infinity], [0, Infinity]])).toBe buffer.lineForRow(0) + + describe "when the range ends after the end of the buffer", -> + it "clips the range to the end of the buffer", -> + expect(buffer.getTextInRange([[12], [13, Infinity]])).toBe buffer.lineForRow(12) + describe ".scanInRange(range, regex, fn)", -> describe "when given a regex with a ignore case flag", -> it "does a case-insensitive search", -> diff --git a/src/app/buffer.coffee b/src/app/buffer.coffee index 95d0819b1..640e21fae 100644 --- a/src/app/buffer.coffee +++ b/src/app/buffer.coffee @@ -115,7 +115,7 @@ class Buffer new Range([0, 0], [@getLastRow(), @getLastLine().length]) getTextInRange: (range) -> - range = Range.fromObject(range) + range = @clipRange(Range.fromObject(range)) if range.start.row == range.end.row return @lineForRow(range.start.row)[range.start.column...range.end.column] @@ -220,6 +220,10 @@ class Buffer new Point(row, column) + clipRange: (range) -> + range = Range.fromObject(range) + new Range(@clipPosition(range.start), @clipPosition(range.end)) + prefixAndSuffixForRange: (range) -> prefix: @lines[range.start.row][0...range.start.column] suffix: @lines[range.end.row][range.end.column..] From 4bfa5dd7a0c0c24bae0cdaf50a72b2f876b835df Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 29 Jan 2013 15:40:34 -0800 Subject: [PATCH 08/80] Remove unneeded Range.fromObject call --- src/app/buffer.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/buffer.coffee b/src/app/buffer.coffee index 640e21fae..9e0cd94ab 100644 --- a/src/app/buffer.coffee +++ b/src/app/buffer.coffee @@ -115,7 +115,7 @@ class Buffer new Range([0, 0], [@getLastRow(), @getLastLine().length]) getTextInRange: (range) -> - range = @clipRange(Range.fromObject(range)) + range = @clipRange(range) if range.start.row == range.end.row return @lineForRow(range.start.row)[range.start.column...range.end.column] From 1303e58a87401b255807b3fd7413722d9b42e683 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 29 Jan 2013 16:09:55 -0800 Subject: [PATCH 09/80] Don't move trailing newline for multiline selections --- spec/app/editor-spec.coffee | 18 ++++++++++++++++++ src/app/edit-session.coffee | 10 ++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index b6dcab74f..9dcffb4cf 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -2351,6 +2351,15 @@ describe "Editor", -> expect(editor.getSelectedBufferRange()).toEqual [[2, 4], [3, 0]] expect(editor.isFoldedAtScreenRow(3)).toBeTruthy() + describe "when an entire line is selected including the newline", -> + it "moves the selected line up", -> + editor.setCursorBufferPosition([1]) + editor.selectToEndOfLine() + editor.selectRight() + editor.trigger 'editor:move-line-up' + expect(buffer.lineForRow(0)).toBe ' var sort = function(items) {' + expect(buffer.lineForRow(1)).toBe 'var quicksort = function () {' + describe "when editor:move-line-down is triggered", -> describe "when there is no selection", -> it "moves the line where the cursor is down", -> @@ -2435,3 +2444,12 @@ describe "Editor", -> expect(buffer.lineForRow(5)).toBe ' while(items.length > 0) {' expect(editor.getSelectedBufferRange()).toEqual [[4, 4], [5, 0]] expect(editor.isFoldedAtScreenRow(5)).toBeTruthy() + + describe "when an entire line is selected including the newline", -> + it "moves the selected line down", -> + editor.setCursorBufferPosition([1]) + editor.selectToEndOfLine() + editor.selectRight() + editor.trigger 'editor:move-line-down' + expect(buffer.lineForRow(1)).toBe ' if (items.length <= 1) return items;' + expect(buffer.lineForRow(2)).toBe ' var sort = function(items) {' diff --git a/src/app/edit-session.coffee b/src/app/edit-session.coffee index fbac2d16f..12adae4d6 100644 --- a/src/app/edit-session.coffee +++ b/src/app/edit-session.coffee @@ -342,7 +342,10 @@ class EditSession @transact => foldedRows = [] - for row in [selection.start.row..selection.end.row] + rows = [selection.start.row..selection.end.row] + if selection.start.row isnt selection.end.row and selection.end.column is 0 + rows.pop() unless @isFoldedAtScreenRow(@screenPositionForBufferPosition(selection.end).row) + for row in rows screenRow = @screenPositionForBufferPosition([row]).row if @isFoldedAtScreenRow(screenRow) bufferRange = @bufferRangeForScreenRange([[screenRow], [screenRow + 1]]) @@ -374,7 +377,10 @@ class EditSession @transact => foldedRows = [] - for row in [selection.end.row..selection.start.row] + rows = [selection.end.row..selection.start.row] + if selection.start.row isnt selection.end.row and selection.end.column is 0 + rows.shift() unless @isFoldedAtScreenRow(@screenPositionForBufferPosition(selection.end).row) + for row in rows screenRow = @screenPositionForBufferPosition([row]).row if @isFoldedAtScreenRow(screenRow) bufferRange = @bufferRangeForScreenRange([[screenRow], [screenRow + 1]]) From 1d2fa089e5cc8e4b054cf1a41cc0f8b90e8af14b Mon Sep 17 00:00:00 2001 From: Corey Johnson & Kevin Sawicki Date: Mon, 28 Jan 2013 12:00:12 -0800 Subject: [PATCH 10/80] editor.wordRegex is now a config option. --- src/app/cursor.coffee | 5 ++--- src/app/editor.coffee | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/cursor.coffee b/src/app/cursor.coffee index 4599705f3..efc80fbf4 100644 --- a/src/app/cursor.coffee +++ b/src/app/cursor.coffee @@ -9,7 +9,6 @@ class Cursor screenPosition: null bufferPosition: null goalColumn: null - wordRegex: /(\w+)|([^\w\n]+)/g visible: true needsAutoscroll: false @@ -150,7 +149,7 @@ class Cursor previousLinesRange = [[previousNonBlankRow, 0], currentBufferPosition] beginningOfWordPosition = currentBufferPosition - @editSession.backwardsScanInRange (options.wordRegex || @wordRegex), previousLinesRange, (match, matchRange, { stop }) => + @editSession.backwardsScanInRange (options.wordRegex ? config.get("editor.wordRegex")), previousLinesRange, (match, matchRange, { stop }) => if matchRange.end.isGreaterThanOrEqual(currentBufferPosition) or allowPrevious beginningOfWordPosition = matchRange.start stop() @@ -162,7 +161,7 @@ class Cursor range = [currentBufferPosition, @editSession.getEofBufferPosition()] endOfWordPosition = null - @editSession.scanInRange (options.wordRegex || @wordRegex), range, (match, matchRange, { stop }) => + @editSession.scanInRange (options.wordRegex ? config.get("editor.wordRegex")), range, (match, matchRange, { stop }) => endOfWordPosition = matchRange.end if not allowNext and matchRange.start.isGreaterThan(currentBufferPosition) endOfWordPosition = currentBufferPosition diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 0fb628d4d..55600c0fa 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -19,6 +19,7 @@ class Editor extends View autosave: false autoIndent: true autoIndentOnPaste: false + wordRegex: /(\w+)|([^\w\n]+)/g @content: (params) -> @div class: @classes(params), tabindex: -1, => From b66efbe3e7137d18d29460ff41735c77c04e9a2c Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Tue, 29 Jan 2013 11:08:17 -0800 Subject: [PATCH 11/80] cursor.getBeginningOfCurrentWordBufferPosition behaves like vim --- spec/app/edit-session-spec.coffee | 10 +++++----- src/app/cursor.coffee | 6 +++++- src/app/editor.coffee | 1 + 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/spec/app/edit-session-spec.coffee b/spec/app/edit-session-spec.coffee index 6f72cd8bc..a16554f84 100644 --- a/spec/app/edit-session-spec.coffee +++ b/spec/app/edit-session-spec.coffee @@ -16,7 +16,7 @@ describe "EditSession", -> afterEach -> fixturesProject.destroy() - describe "cursor", -> + fdescribe "cursor", -> describe ".getCursor()", -> it "returns the most recently created cursor", -> editSession.addCursorAtScreenPosition([1, 0]) @@ -276,17 +276,17 @@ describe "EditSession", -> editSession.moveCursorToBeginningOfWord() expect(cursor1.getBufferPosition()).toEqual [0, 4] - expect(cursor2.getBufferPosition()).toEqual [1, 10] + expect(cursor2.getBufferPosition()).toEqual [1, 11] expect(cursor3.getBufferPosition()).toEqual [2, 39] it "does not fail at position [0, 0]", -> editSession.setCursorBufferPosition([0, 0]) editSession.moveCursorToBeginningOfWord() - it "works when the preceding line is blank", -> - editSession.setCursorBufferPosition([10, 0]) + it "works when the previous line is blank", -> + editSession.setCursorBufferPosition([11, 0]) editSession.moveCursorToBeginningOfWord() - expect(editSession.getCursorBufferPosition()).toEqual [9, 0] + expect(editSession.getCursorBufferPosition()).toEqual [10, 0] describe ".moveCursorToEndOfWord()", -> it "moves the cursor to the end of the word", -> diff --git a/src/app/cursor.coffee b/src/app/cursor.coffee index efc80fbf4..cc4c13c30 100644 --- a/src/app/cursor.coffee +++ b/src/app/cursor.coffee @@ -149,10 +149,14 @@ class Cursor previousLinesRange = [[previousNonBlankRow, 0], currentBufferPosition] beginningOfWordPosition = currentBufferPosition - @editSession.backwardsScanInRange (options.wordRegex ? config.get("editor.wordRegex")), previousLinesRange, (match, matchRange, { stop }) => + + wordSeparators = config.get("editor.wordSeparators") + wordSeparatorsRegex = new RegExp("^[\t ]*\n|[^\\s#{_.escapeRegExp(wordSeparators)}]+|[#{_.escapeRegExp(wordSeparators)}]+", "m") + @editSession.backwardsScanInRange (options.wordRegex ? wordSeparatorsRegex), previousLinesRange, (match, matchRange, { stop }) => if matchRange.end.isGreaterThanOrEqual(currentBufferPosition) or allowPrevious beginningOfWordPosition = matchRange.start stop() + beginningOfWordPosition getEndOfCurrentWordBufferPosition: (options = {}) -> diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 55600c0fa..affeefc68 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -20,6 +20,7 @@ class Editor extends View autoIndent: true autoIndentOnPaste: false wordRegex: /(\w+)|([^\w\n]+)/g + wordSeparators: "./\()\"’-:,.;<>~!@#$%^&*|+=[]{}`~?" @content: (params) -> @div class: @classes(params), tabindex: -1, => From dac92ca6e748cec3d8bcddf361c16fa3a6fca852 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Tue, 29 Jan 2013 12:15:43 -0800 Subject: [PATCH 12/80] Make cursor.moveCursorToBeginningOfWord behave like vim --- spec/app/edit-session-spec.coffee | 28 ++++++++++++++++++++++------ src/app/cursor.coffee | 15 ++++++++++----- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/spec/app/edit-session-spec.coffee b/spec/app/edit-session-spec.coffee index a16554f84..a6c67536f 100644 --- a/spec/app/edit-session-spec.coffee +++ b/spec/app/edit-session-spec.coffee @@ -16,7 +16,7 @@ describe "EditSession", -> afterEach -> fixturesProject.destroy() - fdescribe "cursor", -> + describe "cursor", -> describe ".getCursor()", -> it "returns the most recently created cursor", -> editSession.addCursorAtScreenPosition([1, 0]) @@ -266,7 +266,7 @@ describe "EditSession", -> editSession.moveCursorToFirstCharacterOfLine() expect(editSession.getCursorBufferPosition()).toEqual [10, 0] - describe ".moveCursorToBeginningOfWord()", -> + fdescribe ".moveCursorToBeginningOfWord()", -> it "moves the cursor to the beginning of the word", -> editSession.setCursorBufferPosition [0, 8] editSession.addCursorAtBufferPosition [1, 12] @@ -283,12 +283,17 @@ describe "EditSession", -> editSession.setCursorBufferPosition([0, 0]) editSession.moveCursorToBeginningOfWord() - it "works when the previous line is blank", -> + it "treats lines with only whitespace as a word", -> editSession.setCursorBufferPosition([11, 0]) editSession.moveCursorToBeginningOfWord() expect(editSession.getCursorBufferPosition()).toEqual [10, 0] - describe ".moveCursorToEndOfWord()", -> + it "works when the current line is blank", -> + editSession.setCursorBufferPosition([10, 0]) + editSession.moveCursorToBeginningOfWord() + expect(editSession.getCursorBufferPosition()).toEqual [9, 2] + + fdescribe ".moveCursorToEndOfWord()", -> it "moves the cursor to the end of the word", -> editSession.setCursorBufferPosition [0, 6] editSession.addCursorAtBufferPosition [1, 10] @@ -298,8 +303,8 @@ describe "EditSession", -> editSession.moveCursorToEndOfWord() expect(cursor1.getBufferPosition()).toEqual [0, 13] - expect(cursor2.getBufferPosition()).toEqual [1, 13] - expect(cursor3.getBufferPosition()).toEqual [3, 4] + expect(cursor2.getBufferPosition()).toEqual [1, 12] + expect(cursor3.getBufferPosition()).toEqual [3, 7] it "does not blow up when there is no next word", -> editSession.setCursorBufferPosition [Infinity, Infinity] @@ -307,6 +312,17 @@ describe "EditSession", -> editSession.moveCursorToEndOfWord() expect(editSession.getCursorBufferPosition()).toEqual endPosition + it "treats lines with only whitespace as a word", -> + editSession.setCursorBufferPosition([9, 4]) + editSession.moveCursorToEndOfWord() + expect(editSession.getCursorBufferPosition()).toEqual [10, 0] + + it "works when the current line is blank", -> + editSession.setCursorBufferPosition([10, 0]) + editSession.moveCursorToEndOfWord() + expect(editSession.getCursorBufferPosition()).toEqual [11, 8] + + describe ".getCurrentParagraphBufferRange()", -> it "returns the buffer range of the current paragraph, delimited by blank lines or the beginning / end of the file", -> buffer.setText """ diff --git a/src/app/cursor.coffee b/src/app/cursor.coffee index cc4c13c30..46ff27d5b 100644 --- a/src/app/cursor.coffee +++ b/src/app/cursor.coffee @@ -142,6 +142,10 @@ class Cursor if position = @getEndOfCurrentWordBufferPosition() @setBufferPosition(position) + wordSeparatorsRegExp: -> + wordSeparators = config.get("editor.wordSeparators") + new RegExp("^[\t ]*$|[^\\s#{_.escapeRegExp(wordSeparators)}]+|[#{_.escapeRegExp(wordSeparators)}]+", "mg") + getBeginningOfCurrentWordBufferPosition: (options = {}) -> allowPrevious = options.allowPrevious ? true currentBufferPosition = @getBufferPosition() @@ -150,12 +154,10 @@ class Cursor beginningOfWordPosition = currentBufferPosition - wordSeparators = config.get("editor.wordSeparators") - wordSeparatorsRegex = new RegExp("^[\t ]*\n|[^\\s#{_.escapeRegExp(wordSeparators)}]+|[#{_.escapeRegExp(wordSeparators)}]+", "m") - @editSession.backwardsScanInRange (options.wordRegex ? wordSeparatorsRegex), previousLinesRange, (match, matchRange, { stop }) => + @editSession.backwardsScanInRange (options.wordRegex ? @wordSeparatorsRegExp()), previousLinesRange, (match, matchRange, { stop }) => if matchRange.end.isGreaterThanOrEqual(currentBufferPosition) or allowPrevious beginningOfWordPosition = matchRange.start - stop() + stop() unless beginningOfWordPosition.isEqual(currentBufferPosition) beginningOfWordPosition @@ -165,8 +167,11 @@ class Cursor range = [currentBufferPosition, @editSession.getEofBufferPosition()] endOfWordPosition = null - @editSession.scanInRange (options.wordRegex ? config.get("editor.wordRegex")), range, (match, matchRange, { stop }) => + @editSession.scanInRange (options.wordRegex ? @wordSeparatorsRegExp()), + range, (match, matchRange, { stop }) => endOfWordPosition = matchRange.end + return if endOfWordPosition.isEqual(currentBufferPosition) + if not allowNext and matchRange.start.isGreaterThan(currentBufferPosition) endOfWordPosition = currentBufferPosition stop() From 8973a66cfe6d34cf6407c7a353464be499d6e523 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Tue, 29 Jan 2013 16:33:06 -0800 Subject: [PATCH 13/80] selection.selectWord will consider whitespace a word --- src/app/cursor.coffee | 5 +++++ src/app/selection.coffee | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/app/cursor.coffee b/src/app/cursor.coffee index 46ff27d5b..3f39bb572 100644 --- a/src/app/cursor.coffee +++ b/src/app/cursor.coffee @@ -58,6 +58,11 @@ class Cursor isLastCursor: -> this == @editSession.getCursor() + isSurroundedByWhitespace: -> + {row, column} = @getBufferPosition() + range = [[row, column + 1], [row, Math.max(0, column - 1)]] + /^\s+$/.test @editSession.getTextInBufferRange(range) + autoscrolled: -> @needsAutoscroll = false diff --git a/src/app/selection.coffee b/src/app/selection.coffee index 8123d1157..abc702103 100644 --- a/src/app/selection.coffee +++ b/src/app/selection.coffee @@ -96,7 +96,10 @@ class Selection @screenRangeChanged() selectWord: -> - @setBufferRange(@cursor.getCurrentWordBufferRange()) + options = {} + options.wordRegex = /[\t ]*/ if @cursor.isSurroundedByWhitespace() + + @setBufferRange(@cursor.getCurrentWordBufferRange(options)) @wordwise = true @initialScreenRange = @getScreenRange() From 46aefc75abf6205051519e02e0ee78695e763d27 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Tue, 29 Jan 2013 16:45:24 -0800 Subject: [PATCH 14/80] Make EditSession specs match vim style word behavior --- spec/app/edit-session-spec.coffee | 75 ++++++++++++++++--------------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/spec/app/edit-session-spec.coffee b/spec/app/edit-session-spec.coffee index a6c67536f..327f6ab76 100644 --- a/spec/app/edit-session-spec.coffee +++ b/spec/app/edit-session-spec.coffee @@ -266,7 +266,7 @@ describe "EditSession", -> editSession.moveCursorToFirstCharacterOfLine() expect(editSession.getCursorBufferPosition()).toEqual [10, 0] - fdescribe ".moveCursorToBeginningOfWord()", -> + describe ".moveCursorToBeginningOfWord()", -> it "moves the cursor to the beginning of the word", -> editSession.setCursorBufferPosition [0, 8] editSession.addCursorAtBufferPosition [1, 12] @@ -293,7 +293,7 @@ describe "EditSession", -> editSession.moveCursorToBeginningOfWord() expect(editSession.getCursorBufferPosition()).toEqual [9, 2] - fdescribe ".moveCursorToEndOfWord()", -> + describe ".moveCursorToEndOfWord()", -> it "moves the cursor to the end of the word", -> editSession.setCursorBufferPosition [0, 6] editSession.addCursorAtBufferPosition [1, 10] @@ -534,13 +534,13 @@ describe "EditSession", -> expect(editSession.getCursors().length).toBe 2 [cursor1, cursor2] = editSession.getCursors() expect(cursor1.getBufferPosition()).toEqual [0,4] - expect(cursor2.getBufferPosition()).toEqual [3,44] + expect(cursor2.getBufferPosition()).toEqual [3,47] expect(editSession.getSelections().length).toBe 2 [selection1, selection2] = editSession.getSelections() expect(selection1.getBufferRange()).toEqual [[0,4], [0,13]] expect(selection1.isReversed()).toBeTruthy() - expect(selection2.getBufferRange()).toEqual [[3,44], [3,49]] + expect(selection2.getBufferRange()).toEqual [[3,47], [3,49]] expect(selection2.isReversed()).toBeTruthy() describe ".selectToEndOfWord()", -> @@ -553,40 +553,44 @@ describe "EditSession", -> expect(editSession.getCursors().length).toBe 2 [cursor1, cursor2] = editSession.getCursors() expect(cursor1.getBufferPosition()).toEqual [0,13] - expect(cursor2.getBufferPosition()).toEqual [3,51] + expect(cursor2.getBufferPosition()).toEqual [3,50] expect(editSession.getSelections().length).toBe 2 [selection1, selection2] = editSession.getSelections() expect(selection1.getBufferRange()).toEqual [[0,4], [0,13]] expect(selection1.isReversed()).toBeFalsy() - expect(selection2.getBufferRange()).toEqual [[3,48], [3,51]] + expect(selection2.getBufferRange()).toEqual [[3,48], [3,50]] expect(selection2.isReversed()).toBeFalsy() describe ".selectWord()", -> - describe "when the cursor is inside a word", -> - it "selects the entire word", -> - editSession.setCursorScreenPosition([0, 8]) - editSession.selectWord() - expect(editSession.getSelectedText()).toBe 'quicksort' + describe "when the cursor is inside a word", -> + it "selects the entire word", -> + editSession.setCursorScreenPosition([0, 8]) + editSession.selectWord() + expect(editSession.getSelectedText()).toBe 'quicksort' - describe "when the cursor is between two words", -> - it "selects both words", -> - editSession.setCursorScreenPosition([0, 4]) - editSession.selectWord() - expect(editSession.getSelectedText()).toBe ' quicksort' + describe "when the cursor is between two words", -> + it "selects the nearest word", -> + editSession.setCursorScreenPosition([0, 4]) + editSession.selectWord() + expect(editSession.getSelectedText()).toBe 'quicksort' - describe "when the cursor is inside a region of whitespace", -> - it "selects the whitespace region", -> - editSession.setCursorScreenPosition([5, 2]) - editSession.selectWord() - expect(editSession.getSelectedBufferRange()).toEqual [[5, 0], [5, 6]] + describe "when the cursor is inside a region of whitespace", -> + it "selects the whitespace region", -> + editSession.setCursorScreenPosition([5, 2]) + editSession.selectWord() + expect(editSession.getSelectedBufferRange()).toEqual [[5, 0], [5, 6]] - describe "when the cursor is at the end of the text", -> - it "select the previous word", -> - editSession.buffer.append 'word' - editSession.moveCursorToBottom() - editSession.selectWord() - expect(editSession.getSelectedBufferRange()).toEqual [[12, 2], [12, 6]] + editSession.setCursorScreenPosition([5, 0]) + editSession.selectWord() + expect(editSession.getSelectedBufferRange()).toEqual [[5, 0], [5, 6]] + + describe "when the cursor is at the end of the text", -> + it "select the previous word", -> + editSession.buffer.append 'word' + editSession.moveCursorToBottom() + editSession.selectWord() + expect(editSession.getSelectedBufferRange()).toEqual [[12, 2], [12, 6]] describe ".setSelectedBufferRanges(ranges)", -> it "clears existing selections and creates selections for each of the given ranges", -> @@ -1126,25 +1130,26 @@ describe "EditSession", -> describe "when no text is selected", -> it "deletes all text between the cursor and the beginning of the word", -> editSession.setCursorBufferPosition([1, 24]) - editSession.addCursorAtBufferPosition([2, 5]) + editSession.addCursorAtBufferPosition([3, 5]) [cursor1, cursor2] = editSession.getCursors() editSession.backspaceToBeginningOfWord() expect(buffer.lineForRow(1)).toBe ' var sort = function(ems) {' - expect(buffer.lineForRow(2)).toBe ' f (items.length <= 1) return items;' + expect(buffer.lineForRow(3)).toBe ' ar pivot = items.shift(), current, left = [], right = [];' expect(cursor1.getBufferPosition()).toEqual [1, 22] - expect(cursor2.getBufferPosition()).toEqual [2, 4] + expect(cursor2.getBufferPosition()).toEqual [3, 4] editSession.backspaceToBeginningOfWord() expect(buffer.lineForRow(1)).toBe ' var sort = functionems) {' - expect(buffer.lineForRow(2)).toBe 'f (items.length <= 1) return items;' + expect(buffer.lineForRow(2)).toBe ' if (items.length <= 1) return itemsar pivot = items.shift(), current, left = [], right = [];' expect(cursor1.getBufferPosition()).toEqual [1, 21] - expect(cursor2.getBufferPosition()).toEqual [2, 0] + expect(cursor2.getBufferPosition()).toEqual [2, 39] editSession.backspaceToBeginningOfWord() - expect(buffer.lineForRow(1)).toBe ' var sort = emsf (items.length <= 1) return items;' + expect(buffer.lineForRow(1)).toBe ' var sort = ems) {' + expect(buffer.lineForRow(2)).toBe ' if (items.length <= 1) return ar pivot = items.shift(), current, left = [], right = [];' expect(cursor1.getBufferPosition()).toEqual [1, 13] - expect(cursor2.getBufferPosition()).toEqual [1, 16] + expect(cursor2.getBufferPosition()).toEqual [2, 34] describe "when text is selected", -> it "deletes only selected text", -> @@ -1312,7 +1317,7 @@ describe "EditSession", -> expect(cursor2.getBufferPosition()).toEqual [2, 5] editSession.deleteToEndOfWord() - expect(buffer.lineForRow(1)).toBe ' var sort = function(it' + expect(buffer.lineForRow(1)).toBe ' var sort = function(it {' expect(buffer.lineForRow(2)).toBe ' iitems.length <= 1) return items;' expect(cursor1.getBufferPosition()).toEqual [1, 24] expect(cursor2.getBufferPosition()).toEqual [2, 5] From 167b9c28fa7355c715dc19fdd360e64787e9b369 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Tue, 29 Jan 2013 17:06:39 -0800 Subject: [PATCH 15/80] Rename wordSeparators to nonWordCharacters --- src/app/cursor.coffee | 10 +++++----- src/app/editor.coffee | 3 +-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/app/cursor.coffee b/src/app/cursor.coffee index 3f39bb572..aaffe22d6 100644 --- a/src/app/cursor.coffee +++ b/src/app/cursor.coffee @@ -147,9 +147,9 @@ class Cursor if position = @getEndOfCurrentWordBufferPosition() @setBufferPosition(position) - wordSeparatorsRegExp: -> - wordSeparators = config.get("editor.wordSeparators") - new RegExp("^[\t ]*$|[^\\s#{_.escapeRegExp(wordSeparators)}]+|[#{_.escapeRegExp(wordSeparators)}]+", "mg") + wordRegExp: -> + nonWordCharacters = config.get("editor.nonWordCharacters") + new RegExp("^[\t ]*$|[^\\s#{_.escapeRegExp(nonWordCharacters)}]+|[#{_.escapeRegExp(nonWordCharacters)}]+", "mg") getBeginningOfCurrentWordBufferPosition: (options = {}) -> allowPrevious = options.allowPrevious ? true @@ -159,7 +159,7 @@ class Cursor beginningOfWordPosition = currentBufferPosition - @editSession.backwardsScanInRange (options.wordRegex ? @wordSeparatorsRegExp()), previousLinesRange, (match, matchRange, { stop }) => + @editSession.backwardsScanInRange (options.wordRegex ? @wordRegExp()), previousLinesRange, (match, matchRange, { stop }) => if matchRange.end.isGreaterThanOrEqual(currentBufferPosition) or allowPrevious beginningOfWordPosition = matchRange.start stop() unless beginningOfWordPosition.isEqual(currentBufferPosition) @@ -172,7 +172,7 @@ class Cursor range = [currentBufferPosition, @editSession.getEofBufferPosition()] endOfWordPosition = null - @editSession.scanInRange (options.wordRegex ? @wordSeparatorsRegExp()), + @editSession.scanInRange (options.wordRegex ? @wordRegExp()), range, (match, matchRange, { stop }) => endOfWordPosition = matchRange.end return if endOfWordPosition.isEqual(currentBufferPosition) diff --git a/src/app/editor.coffee b/src/app/editor.coffee index affeefc68..bdd25ba67 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -19,8 +19,7 @@ class Editor extends View autosave: false autoIndent: true autoIndentOnPaste: false - wordRegex: /(\w+)|([^\w\n]+)/g - wordSeparators: "./\()\"’-:,.;<>~!@#$%^&*|+=[]{}`~?" + nonWordCharacters: "./\()\"’-:,.;<>~!@#$%^&*|+=[]{}`~?" @content: (params) -> @div class: @classes(params), tabindex: -1, => From c71f58a65231c3622ee7e5a1ea8529e35901efb2 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Tue, 29 Jan 2013 17:08:07 -0800 Subject: [PATCH 16/80] :lipstick: --- src/app/cursor.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/cursor.coffee b/src/app/cursor.coffee index aaffe22d6..c3e0a0591 100644 --- a/src/app/cursor.coffee +++ b/src/app/cursor.coffee @@ -55,6 +55,10 @@ class Cursor isVisible: -> @visible + wordRegExp: -> + nonWordCharacters = config.get("editor.nonWordCharacters") + new RegExp("^[\t ]*$|[^\\s#{_.escapeRegExp(nonWordCharacters)}]+|[#{_.escapeRegExp(nonWordCharacters)}]+", "mg") + isLastCursor: -> this == @editSession.getCursor() @@ -147,10 +151,6 @@ class Cursor if position = @getEndOfCurrentWordBufferPosition() @setBufferPosition(position) - wordRegExp: -> - nonWordCharacters = config.get("editor.nonWordCharacters") - new RegExp("^[\t ]*$|[^\\s#{_.escapeRegExp(nonWordCharacters)}]+|[#{_.escapeRegExp(nonWordCharacters)}]+", "mg") - getBeginningOfCurrentWordBufferPosition: (options = {}) -> allowPrevious = options.allowPrevious ? true currentBufferPosition = @getBufferPosition() From c32836ad2c1b9e4e3e7b8f318aaa15d535de28e4 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Tue, 29 Jan 2013 17:10:27 -0800 Subject: [PATCH 17/80] _ and - both considered non word characters. Fixes #82 Maybe @defunkt wanted the reverse though (consider _ and - word characters)? Either way, it's a config option you can change now. --- src/app/editor.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/editor.coffee b/src/app/editor.coffee index bdd25ba67..9a6710d8e 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -19,7 +19,7 @@ class Editor extends View autosave: false autoIndent: true autoIndentOnPaste: false - nonWordCharacters: "./\()\"’-:,.;<>~!@#$%^&*|+=[]{}`~?" + nonWordCharacters: "./\()\"’-_:,.;<>~!@#$%^&*|+=[]{}`~?" @content: (params) -> @div class: @classes(params), tabindex: -1, => From a34b9296e9c38da457f95245fea450caa6eb1444 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Tue, 29 Jan 2013 17:14:10 -0800 Subject: [PATCH 18/80] Escape \ in editor.nonWordCharachters --- src/app/editor.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 9a6710d8e..7d4ee0382 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -19,7 +19,7 @@ class Editor extends View autosave: false autoIndent: true autoIndentOnPaste: false - nonWordCharacters: "./\()\"’-_:,.;<>~!@#$%^&*|+=[]{}`~?" + nonWordCharacters: "./\\()\"’-_:,.;<>~!@#$%^&*|+=[]{}`~?" @content: (params) -> @div class: @classes(params), tabindex: -1, => From 05314ae2150298fca37b63c2691d9f534a1f4706 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 29 Jan 2013 17:16:33 -0800 Subject: [PATCH 19/80] Call delete() from deleteRows() --- src/app/buffer.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/buffer.coffee b/src/app/buffer.coffee index 9e0cd94ab..db7de2e75 100644 --- a/src/app/buffer.coffee +++ b/src/app/buffer.coffee @@ -194,7 +194,7 @@ class Buffer startPoint = [start, 0] endPoint = [end + 1, 0] - @change(new Range(startPoint, endPoint), '') + @delete(new Range(startPoint, endPoint)) append: (text) -> @insert(@getEofPosition(), text) From 7a186b1ab64e6f0e7838e2687fe3373ef3c6361d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 29 Jan 2013 18:21:38 -0800 Subject: [PATCH 20/80] Add python bundle as submodule --- .gitmodules | 3 +++ vendor/packages/python.tmbundle | 1 + 2 files changed, 4 insertions(+) create mode 160000 vendor/packages/python.tmbundle diff --git a/.gitmodules b/.gitmodules index caa40d8c9..6495d34a2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -43,3 +43,6 @@ [submodule "vendor/packages/property-list.tmbundle"] path = vendor/packages/property-list.tmbundle url = https://github.com/textmate/property-list.tmbundle.git +[submodule "vendor/packages/python.tmbundle"] + path = vendor/packages/python.tmbundle + url = https://github.com/textmate/python.tmbundle diff --git a/vendor/packages/python.tmbundle b/vendor/packages/python.tmbundle new file mode 160000 index 000000000..3675c22ae --- /dev/null +++ b/vendor/packages/python.tmbundle @@ -0,0 +1 @@ +Subproject commit 3675c22ae891419b27a80c58001831d01e73d431 From 1a8986aae2f5d0035252e4761879ee76b6bd1913 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Wed, 30 Jan 2013 08:02:19 -0800 Subject: [PATCH 21/80] Fix start/end for range --- src/app/cursor.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/cursor.coffee b/src/app/cursor.coffee index c3e0a0591..bf6e058ae 100644 --- a/src/app/cursor.coffee +++ b/src/app/cursor.coffee @@ -64,7 +64,7 @@ class Cursor isSurroundedByWhitespace: -> {row, column} = @getBufferPosition() - range = [[row, column + 1], [row, Math.max(0, column - 1)]] + range = [[row, Math.min(0, column - 1)], [row, Math.max(0, column + 1)]] /^\s+$/.test @editSession.getTextInBufferRange(range) autoscrolled: -> From 086c7ef98712ae824f3296a5192edf95d1ac7ace Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Wed, 30 Jan 2013 08:15:28 -0800 Subject: [PATCH 22/80] multiline regex not needed --- src/app/cursor.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/cursor.coffee b/src/app/cursor.coffee index bf6e058ae..04d13ee37 100644 --- a/src/app/cursor.coffee +++ b/src/app/cursor.coffee @@ -57,7 +57,7 @@ class Cursor wordRegExp: -> nonWordCharacters = config.get("editor.nonWordCharacters") - new RegExp("^[\t ]*$|[^\\s#{_.escapeRegExp(nonWordCharacters)}]+|[#{_.escapeRegExp(nonWordCharacters)}]+", "mg") + new RegExp("^[\t ]*$|[^\\s#{_.escapeRegExp(nonWordCharacters)}]+|[#{_.escapeRegExp(nonWordCharacters)}]+", "g") isLastCursor: -> this == @editSession.getCursor() From f698d7e9dcff5c9aebef3064d7d9236ccdcd3c17 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Wed, 30 Jan 2013 08:20:11 -0800 Subject: [PATCH 23/80] :lipstick: --- src/app/cursor.coffee | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/app/cursor.coffee b/src/app/cursor.coffee index 04d13ee37..659e91e43 100644 --- a/src/app/cursor.coffee +++ b/src/app/cursor.coffee @@ -155,16 +155,16 @@ class Cursor allowPrevious = options.allowPrevious ? true currentBufferPosition = @getBufferPosition() previousNonBlankRow = @editSession.buffer.previousNonBlankRow(currentBufferPosition.row) - previousLinesRange = [[previousNonBlankRow, 0], currentBufferPosition] + range = [[previousNonBlankRow, 0], currentBufferPosition] - beginningOfWordPosition = currentBufferPosition - - @editSession.backwardsScanInRange (options.wordRegex ? @wordRegExp()), previousLinesRange, (match, matchRange, { stop }) => + beginningOfWordPosition = null + @editSession.backwardsScanInRange (options.wordRegex ? @wordRegExp()), range, (match, matchRange, { stop }) => if matchRange.end.isGreaterThanOrEqual(currentBufferPosition) or allowPrevious beginningOfWordPosition = matchRange.start - stop() unless beginningOfWordPosition.isEqual(currentBufferPosition) + if not beginningOfWordPosition?.isEqual(currentBufferPosition) + stop() - beginningOfWordPosition + beginningOfWordPosition or currentBufferPosition getEndOfCurrentWordBufferPosition: (options = {}) -> allowNext = options.allowNext ? true @@ -172,14 +172,13 @@ class Cursor range = [currentBufferPosition, @editSession.getEofBufferPosition()] endOfWordPosition = null - @editSession.scanInRange (options.wordRegex ? @wordRegExp()), - range, (match, matchRange, { stop }) => + @editSession.scanInRange (options.wordRegex ? @wordRegExp()), range, (match, matchRange, { stop }) => endOfWordPosition = matchRange.end - return if endOfWordPosition.isEqual(currentBufferPosition) - - if not allowNext and matchRange.start.isGreaterThan(currentBufferPosition) + if matchRange.start.isGreaterThan(currentBufferPosition) and not allowNext endOfWordPosition = currentBufferPosition - stop() + if not endOfWordPosition.isEqual(currentBufferPosition) + stop() + endOfWordPosition or currentBufferPosition getCurrentWordBufferRange: (options={}) -> From 97fa9d522a05b00aa3299196015859af10ec9626 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Wed, 30 Jan 2013 08:39:32 -0800 Subject: [PATCH 24/80] end/beginning word implementations are now more similar --- spec/app/edit-session-spec.coffee | 7 ++++++- src/app/cursor.coffee | 7 +++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/spec/app/edit-session-spec.coffee b/spec/app/edit-session-spec.coffee index 327f6ab76..c77ddd15c 100644 --- a/spec/app/edit-session-spec.coffee +++ b/spec/app/edit-session-spec.coffee @@ -570,11 +570,16 @@ describe "EditSession", -> expect(editSession.getSelectedText()).toBe 'quicksort' describe "when the cursor is between two words", -> - it "selects the nearest word", -> + it "selects the word the cursor is on", -> editSession.setCursorScreenPosition([0, 4]) editSession.selectWord() expect(editSession.getSelectedText()).toBe 'quicksort' + editSession.setCursorScreenPosition([0, 3]) + editSession.selectWord() + expect(editSession.getSelectedText()).toBe 'var' + + describe "when the cursor is inside a region of whitespace", -> it "selects the whitespace region", -> editSession.setCursorScreenPosition([5, 2]) diff --git a/src/app/cursor.coffee b/src/app/cursor.coffee index 659e91e43..8ac44739e 100644 --- a/src/app/cursor.coffee +++ b/src/app/cursor.coffee @@ -173,10 +173,9 @@ class Cursor endOfWordPosition = null @editSession.scanInRange (options.wordRegex ? @wordRegExp()), range, (match, matchRange, { stop }) => - endOfWordPosition = matchRange.end - if matchRange.start.isGreaterThan(currentBufferPosition) and not allowNext - endOfWordPosition = currentBufferPosition - if not endOfWordPosition.isEqual(currentBufferPosition) + if matchRange.start.isLessThanOrEqual(currentBufferPosition) or allowNext + endOfWordPosition = matchRange.end + if not endOfWordPosition?.isEqual(currentBufferPosition) stop() endOfWordPosition or currentBufferPosition From 4db876aed130f62497dafc0f96782f5123f8e56f Mon Sep 17 00:00:00 2001 From: Corey Johnson & Kevin Sawicki Date: Wed, 30 Jan 2013 09:08:12 -0800 Subject: [PATCH 25/80] Deleting before fold no longer unfolds after undo Use same row delta computation for updating start and end rows in folds. --- spec/app/display-buffer-spec.coffee | 14 ++++++++++++++ src/app/fold.coffee | 30 ++++++++--------------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/spec/app/display-buffer-spec.coffee b/spec/app/display-buffer-spec.coffee index cd7ca484c..7444a3859 100644 --- a/spec/app/display-buffer-spec.coffee +++ b/spec/app/display-buffer-spec.coffee @@ -495,6 +495,20 @@ describe "DisplayBuffer", -> expect(displayBuffer.lineForRow(8).text).toMatch /^9-+/ expect(displayBuffer.lineForRow(10).fold).toBeDefined() + describe "when the line being deleted preceeds a fold", -> + describe "when the command is undone", -> + it "restores the line and preserves the fold", -> + editSession.setCursorBufferPosition([4]) + editSession.foldCurrentRow() + expect(editSession.isFoldedAtScreenRow(4)).toBeTruthy() + editSession.setCursorBufferPosition([3]) + editSession.deleteLine() + expect(editSession.isFoldedAtScreenRow(3)).toBeTruthy() + expect(buffer.lineForRow(3)).toBe ' while(items.length > 0) {' + editSession.undo() + expect(editSession.isFoldedAtScreenRow(4)).toBeTruthy() + expect(buffer.lineForRow(3)).toBe ' var pivot = items.shift(), current, left = [], right = [];' + describe ".clipScreenPosition(screenPosition, wrapBeyondNewlines: false, wrapAtSoftNewlines: false, skipAtomicTokens: false)", -> beforeEach -> displayBuffer.setSoftWrapColumn(50) diff --git a/src/app/fold.coffee b/src/app/fold.coffee index 57bea3cfa..50e5d34ba 100644 --- a/src/app/fold.coffee +++ b/src/app/fold.coffee @@ -36,8 +36,8 @@ class Fold @displayBuffer.unregisterFold(@startRow, this) return - @updateStartRow(event) - @updateEndRow(event) + @startRow += @getRowDelta(event, @startRow) + @endRow += @getRowDelta(event, @endRow) if @startRow != oldStartRow @displayBuffer.unregisterFold(oldStartRow, this) @@ -49,26 +49,12 @@ class Fold isContainedByFold: (fold) -> @isContainedByRange(fold.getBufferRange()) - updateStartRow: (event) -> + getRowDelta: (event, row) -> { newRange, oldRange } = event - if oldRange.end.row < @startRow - delta = newRange.end.row - oldRange.end.row - else if newRange.end.row < @startRow - delta = newRange.end.row - @startRow + if oldRange.end.row <= row + newRange.end.row - oldRange.end.row + else if newRange.end.row < row + newRange.end.row - row else - delta = 0 - - @startRow += delta - - updateEndRow: (event) -> - { newRange, oldRange } = event - - if oldRange.end.row <= @endRow - delta = newRange.end.row - oldRange.end.row - else if newRange.end.row <= @endRow - delta = newRange.end.row - @endRow - else - delta = 0 - - @endRow += delta + 0 From a83460452e33b147774b80da145de2660f0e0c8f Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Tue, 15 Jan 2013 16:21:55 -0800 Subject: [PATCH 26/80] add config option for setting the font family --- src/app/editor.coffee | 23 ++++++++++++++++++----- static/editor.css | 2 +- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 7d4ee0382..74b3e8765 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -14,6 +14,7 @@ _ = require 'underscore' module.exports = class Editor extends View @configDefaults: + fontFamily: "Inconsolata, Monaco, Courier" fontSize: 20 showInvisibles: false autosave: false @@ -340,6 +341,7 @@ class Editor extends View @observeConfig 'editor.showInvisibles', (showInvisibles) => @setShowInvisibles(showInvisibles) @observeConfig 'editor.invisibles', (invisibles) => @setInvisibles(invisibles) @observeConfig 'editor.fontSize', (fontSize) => @setFontSize(fontSize) + @observeConfig 'editor.fontFamily', (fontFamily) => @setFontFamily(fontFamily) handleEvents: -> @on 'focus', => @@ -683,14 +685,25 @@ class Editor extends View setFontSize: (@fontSize) -> if fontSize? @css('font-size', fontSize + 'px') - return unless @attached - @calculateDimensions() - @updatePaddingOfRenderedLines() - @updateLayerDimensions() - @requestDisplayUpdate() + @redraw() getFontSize: -> @fontSize + setFontFamily: (@fontFamily) -> + if fontFamily? + @css('font-family', fontFamily) + @redraw() + + getFontFamily: -> @fontFamily + + + redraw: -> + return unless @attached + @calculateDimensions() + @updatePaddingOfRenderedLines() + @updateLayerDimensions() + @requestDisplayUpdate() + newSplitEditor: (editSession) -> new Editor { editSession: editSession ? @activeEditSession.copy() } diff --git a/static/editor.css b/static/editor.css index bdd9f2825..0b8cfb452 100644 --- a/static/editor.css +++ b/static/editor.css @@ -103,4 +103,4 @@ position: absolute; pointer-events: none; z-index: -1; -} \ No newline at end of file +} From f138a29a879ffd356419058b1de85c18e40a07bb Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Tue, 15 Jan 2013 16:23:02 -0800 Subject: [PATCH 27/80] add config option for line height This renames the original lineHeight variable to rowHeight to avoid collision --- src/app/editor.coffee | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 74b3e8765..75396cd2a 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -16,6 +16,7 @@ class Editor extends View @configDefaults: fontFamily: "Inconsolata, Monaco, Courier" fontSize: 20 + lineHeight: 1.5 showInvisibles: false autosave: false autoIndent: true @@ -308,7 +309,7 @@ class Editor extends View @scrollTop(newScrollTop, adjustVerticalScrollbar: true) getPageRows: -> - Math.max(1, Math.ceil(@scrollView[0].clientHeight / @lineHeight)) + Math.max(1, Math.ceil(@scrollView[0].clientHeight / @rowHeight)) setShowInvisibles: (showInvisibles) -> return if showInvisibles == @showInvisibles @@ -342,6 +343,7 @@ class Editor extends View @observeConfig 'editor.invisibles', (invisibles) => @setInvisibles(invisibles) @observeConfig 'editor.fontSize', (fontSize) => @setFontSize(fontSize) @observeConfig 'editor.fontFamily', (fontFamily) => @setFontFamily(fontFamily) + @observeConfig 'editor.lineHeight', (lineHeight) => @setLineHeight(lineHeight) handleEvents: -> @on 'focus', => @@ -575,7 +577,7 @@ class Editor extends View @scrollTop() + @scrollView.height() scrollToBottom: -> - @scrollBottom(@screenLineCount() * @lineHeight) + @scrollBottom(@screenLineCount() * @rowHeight) scrollToBufferPosition: (bufferPosition, options) -> @scrollToPixelPosition(@pixelPositionForBufferPosition(bufferPosition), options) @@ -597,12 +599,12 @@ class Editor extends View unless scrollTop < pixelPosition.top < scrollBottom @scrollTop(pixelPosition.top - (scrollViewHeight / 2)) else - linesInView = @scrollView.height() / @lineHeight + linesInView = @scrollView.height() / @rowHeight maxScrollMargin = Math.floor((linesInView - 1) / 2) scrollMargin = Math.min(@vScrollMargin, maxScrollMargin) - margin = scrollMargin * @lineHeight + margin = scrollMargin * @rowHeight desiredTop = pixelPosition.top - margin - desiredBottom = pixelPosition.top + @lineHeight + margin + desiredBottom = pixelPosition.top + @rowHeight + margin if desiredBottom > scrollBottom @scrollTop(desiredBottom - scrollViewHeight) else if desiredTop < scrollTop @@ -696,6 +698,12 @@ class Editor extends View getFontFamily: -> @fontFamily + setLineHeight: (@lineHeight) -> + if lineHeight? + @css('line-height', "#{lineHeight}em") + @redraw() + + getLineHeight: -> @lineHeight redraw: -> return unless @attached @@ -798,16 +806,16 @@ class Editor extends View lineRect = fragment[0].getBoundingClientRect() charRect = fragment.find('span')[0].getBoundingClientRect() - @lineHeight = lineRect.height + @rowHeight = lineRect.height @charWidth = charRect.width @charHeight = charRect.height - @height(@lineHeight) if @mini + @height(@rowHeight) if @mini fragment.remove() updateLayerDimensions: -> @gutter.calculateWidth() - height = @lineHeight * @screenLineCount() + height = @rowHeight * @screenLineCount() unless @layerHeight == height @renderedLines.height(height) @underlayer.css('min-height', height) @@ -1015,19 +1023,19 @@ class Editor extends View row++ updatePaddingOfRenderedLines: -> - paddingTop = @firstRenderedScreenRow * @lineHeight + paddingTop = @firstRenderedScreenRow * @rowHeight @renderedLines.css('padding-top', paddingTop) @gutter.lineNumbers.css('padding-top', paddingTop) - paddingBottom = (@getLastScreenRow() - @lastRenderedScreenRow) * @lineHeight + paddingBottom = (@getLastScreenRow() - @lastRenderedScreenRow) * @rowHeight @renderedLines.css('padding-bottom', paddingBottom) @gutter.lineNumbers.css('padding-bottom', paddingBottom) getFirstVisibleScreenRow: -> - Math.floor(@scrollTop() / @lineHeight) + Math.floor(@scrollTop() / @rowHeight) getLastVisibleScreenRow: -> - Math.max(0, Math.ceil((@scrollTop() + @scrollView.height()) / @lineHeight) - 1) + Math.max(0, Math.ceil((@scrollTop() + @scrollView.height()) / @rowHeight) - 1) isScreenRowVisible: (row) -> @getFirstVisibleScreenRow() <= row <= @getLastVisibleScreenRow() @@ -1126,7 +1134,7 @@ class Editor extends View pixelPositionForScreenPosition: (position) -> position = Point.fromObject(position) - { top: position.row * @lineHeight, left: position.column * @charWidth } + { top: position.row * @rowHeight, left: position.column * @charWidth } pixelOffsetForScreenPosition: (position) -> {top, left} = @pixelPositionForScreenPosition(position) @@ -1134,7 +1142,7 @@ class Editor extends View {top: top + offset.top, left: left + offset.left} screenPositionFromPixelPosition: ({top, left}) -> - screenPosition = new Point(Math.floor(top / @lineHeight), Math.floor(left / @charWidth)) + screenPosition = new Point(Math.floor(top / @rowHeight), Math.floor(left / @charWidth)) screenPositionFromMouseEvent: (e) -> { pageX, pageY } = e From e17387e7f0f6f6279286fefda72ea1b90409a23c Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Thu, 24 Jan 2013 11:36:25 -0800 Subject: [PATCH 28/80] Remove lineHeight example from docs --- docs/configuring-and-extending.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/configuring-and-extending.md b/docs/configuring-and-extending.md index 7ecd60a04..35ece3c59 100644 --- a/docs/configuring-and-extending.md +++ b/docs/configuring-and-extending.md @@ -55,8 +55,8 @@ Or you can use `observeConfig` to track changes from a view object. ```coffeescript class MyView extends View initialize: -> - @observeConfig 'editor.lineHeight', (lineHeight) => - @adjustLineHeight(lineHeight) + @observeConfig 'editor.fontSize', () => + @adjustFontSize() ``` The `observeConfig` method will call the given callback immediately with the From 129b574df4f44650c928d9e250e9b3d29127128d Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Thu, 24 Jan 2013 11:37:23 -0800 Subject: [PATCH 29/80] Remove lineHeight config option and rename @rowHeight back to @lineHeight --- src/app/editor.coffee | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 75396cd2a..875e4163a 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -16,7 +16,6 @@ class Editor extends View @configDefaults: fontFamily: "Inconsolata, Monaco, Courier" fontSize: 20 - lineHeight: 1.5 showInvisibles: false autosave: false autoIndent: true @@ -309,7 +308,7 @@ class Editor extends View @scrollTop(newScrollTop, adjustVerticalScrollbar: true) getPageRows: -> - Math.max(1, Math.ceil(@scrollView[0].clientHeight / @rowHeight)) + Math.max(1, Math.ceil(@scrollView[0].clientHeight / @lineHeight)) setShowInvisibles: (showInvisibles) -> return if showInvisibles == @showInvisibles @@ -343,7 +342,6 @@ class Editor extends View @observeConfig 'editor.invisibles', (invisibles) => @setInvisibles(invisibles) @observeConfig 'editor.fontSize', (fontSize) => @setFontSize(fontSize) @observeConfig 'editor.fontFamily', (fontFamily) => @setFontFamily(fontFamily) - @observeConfig 'editor.lineHeight', (lineHeight) => @setLineHeight(lineHeight) handleEvents: -> @on 'focus', => @@ -577,7 +575,7 @@ class Editor extends View @scrollTop() + @scrollView.height() scrollToBottom: -> - @scrollBottom(@screenLineCount() * @rowHeight) + @scrollBottom(@screenLineCount() * @lineHeight) scrollToBufferPosition: (bufferPosition, options) -> @scrollToPixelPosition(@pixelPositionForBufferPosition(bufferPosition), options) @@ -599,12 +597,12 @@ class Editor extends View unless scrollTop < pixelPosition.top < scrollBottom @scrollTop(pixelPosition.top - (scrollViewHeight / 2)) else - linesInView = @scrollView.height() / @rowHeight + linesInView = @scrollView.height() / @lineHeight maxScrollMargin = Math.floor((linesInView - 1) / 2) scrollMargin = Math.min(@vScrollMargin, maxScrollMargin) - margin = scrollMargin * @rowHeight + margin = scrollMargin * @lineHeight desiredTop = pixelPosition.top - margin - desiredBottom = pixelPosition.top + @rowHeight + margin + desiredBottom = pixelPosition.top + @lineHeight + margin if desiredBottom > scrollBottom @scrollTop(desiredBottom - scrollViewHeight) else if desiredTop < scrollTop @@ -698,13 +696,6 @@ class Editor extends View getFontFamily: -> @fontFamily - setLineHeight: (@lineHeight) -> - if lineHeight? - @css('line-height', "#{lineHeight}em") - @redraw() - - getLineHeight: -> @lineHeight - redraw: -> return unless @attached @calculateDimensions() @@ -806,16 +797,16 @@ class Editor extends View lineRect = fragment[0].getBoundingClientRect() charRect = fragment.find('span')[0].getBoundingClientRect() - @rowHeight = lineRect.height + @lineHeight = lineRect.height @charWidth = charRect.width @charHeight = charRect.height - @height(@rowHeight) if @mini + @height(@lineHeight) if @mini fragment.remove() updateLayerDimensions: -> @gutter.calculateWidth() - height = @rowHeight * @screenLineCount() + height = @lineHeight * @screenLineCount() unless @layerHeight == height @renderedLines.height(height) @underlayer.css('min-height', height) @@ -1023,19 +1014,19 @@ class Editor extends View row++ updatePaddingOfRenderedLines: -> - paddingTop = @firstRenderedScreenRow * @rowHeight + paddingTop = @firstRenderedScreenRow * @lineHeight @renderedLines.css('padding-top', paddingTop) @gutter.lineNumbers.css('padding-top', paddingTop) - paddingBottom = (@getLastScreenRow() - @lastRenderedScreenRow) * @rowHeight + paddingBottom = (@getLastScreenRow() - @lastRenderedScreenRow) * @lineHeight @renderedLines.css('padding-bottom', paddingBottom) @gutter.lineNumbers.css('padding-bottom', paddingBottom) getFirstVisibleScreenRow: -> - Math.floor(@scrollTop() / @rowHeight) + Math.floor(@scrollTop() / @lineHeight) getLastVisibleScreenRow: -> - Math.max(0, Math.ceil((@scrollTop() + @scrollView.height()) / @rowHeight) - 1) + Math.max(0, Math.ceil((@scrollTop() + @scrollView.height()) / @lineHeight) - 1) isScreenRowVisible: (row) -> @getFirstVisibleScreenRow() <= row <= @getLastVisibleScreenRow() @@ -1134,7 +1125,7 @@ class Editor extends View pixelPositionForScreenPosition: (position) -> position = Point.fromObject(position) - { top: position.row * @rowHeight, left: position.column * @charWidth } + { top: position.row * @lineHeight, left: position.column * @charWidth } pixelOffsetForScreenPosition: (position) -> {top, left} = @pixelPositionForScreenPosition(position) @@ -1142,7 +1133,7 @@ class Editor extends View {top: top + offset.top, left: left + offset.left} screenPositionFromPixelPosition: ({top, left}) -> - screenPosition = new Point(Math.floor(top / @rowHeight), Math.floor(left / @charWidth)) + screenPosition = new Point(Math.floor(top / @lineHeight), Math.floor(left / @charWidth)) screenPositionFromMouseEvent: (e) -> { pageX, pageY } = e From e7c3282f53ec3bd92894cbbed871bf0d5db4f321 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Wed, 30 Jan 2013 10:15:34 -0800 Subject: [PATCH 30/80] Add font-family spec --- spec/app/editor-spec.coffee | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index 9dcffb4cf..2660b14fa 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -516,6 +516,30 @@ describe "Editor", -> editor.getBuffer().saveAs(path) expect(editor.getGrammar().name).toBe 'Plain Text' + describe "font family", -> + beforeEach -> + expect(editor.css('font-family')).not.toBe 'monaco' + + it "sets the initial font family based on the value from config", -> + config.set("editor.fontFamily", "monaco") + newEditor = editor.splitRight() + expect(editor.css('font-family')).toBe 'monaco' + expect(newEditor.css('font-family')).toBe 'monaco' + + describe "when the font family changes on the view", -> + it "updates the font family of editors and recalculates dimensions critical to cursor positioning", -> + rootView.attachToDom() + rootView.height(200) + rootView.width(200) + + lineHeightBefore = editor.lineHeight + charWidthBefore = editor.charWidth + editor.setCursorScreenPosition [5, 6] + config.set("editor.fontFamily", "monaco") + expect(editor.charWidth).not.toBe charWidthBefore + expect(editor.getCursorView().position()).toEqual { top: 5 * editor.lineHeight, left: 6 * editor.charWidth } + expect(editor.verticalScrollbarContent.height()).toBe buffer.getLineCount() * editor.lineHeight + describe "font size", -> it "sets the initial font size based on the value from config", -> config.set("editor.fontSize", 20) From 6c10622b2faa4ac2143d6b7ddedf6b544630824a Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Wed, 30 Jan 2013 10:57:44 -0800 Subject: [PATCH 31/80] support escape key to exit command panel --- src/packages/command-panel/src/command-panel-view.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/packages/command-panel/src/command-panel-view.coffee b/src/packages/command-panel/src/command-panel-view.coffee index 7ccb74a48..b297516df 100644 --- a/src/packages/command-panel/src/command-panel-view.coffee +++ b/src/packages/command-panel/src/command-panel-view.coffee @@ -44,6 +44,7 @@ class CommandPanelView extends View @command 'tool-panel:unfocus', => @rootView.focus() @command 'core:close', => @detach(); false + @command 'core:cancel', => @detach(); false @command 'core:confirm', => @execute() @command 'core:move-up', => @navigateBackwardInHistory() @command 'core:move-down', => @navigateForwardInHistory() From 8dbcefa9327defa03f2f7202fd7fbfc5bba14aa7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 30 Jan 2013 11:48:58 -0800 Subject: [PATCH 32/80] Style color of folded line numbers --- spec/app/editor-spec.coffee | 5 +++++ src/app/edit-session.coffee | 4 ++++ src/app/editor.coffee | 1 + src/app/gutter.coffee | 9 ++++++--- themes/Atom - Dark/editor.css | 11 ++++++++++- themes/Atom - Light/editor.css | 11 ++++++++++- 6 files changed, 36 insertions(+), 5 deletions(-) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index 9dcffb4cf..753aa7c85 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -1730,6 +1730,11 @@ describe "Editor", -> fold.destroy() expect(editor.gutter.find('.line-number').length).toBe 13 + it "styles folded line numbers", -> + editor.createFold(3, 5) + expect(editor.gutter.find('.line-number.fold').length).toBe 1 + expect(editor.gutter.find('.line-number.fold:eq(0)').text()).toBe '4' + describe "when the scrollView is scrolled to the right", -> it "adds a drop shadow to the gutter", -> editor.attachToDom() diff --git a/src/app/edit-session.coffee b/src/app/edit-session.coffee index 12adae4d6..f0be412a5 100644 --- a/src/app/edit-session.coffee +++ b/src/app/edit-session.coffee @@ -307,6 +307,10 @@ class EditSession fold.destroy() @setCursorBufferPosition([fold.startRow, 0]) + isFoldedAtBufferRow: (bufferRow) -> + screenRow = @screenPositionForBufferPosition([bufferRow]).row + @isFoldedAtScreenRow(screenRow) + isFoldedAtScreenRow: (screenRow) -> @lineForScreenRow(screenRow)?.fold? diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 7d4ee0382..6daf0f276 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -276,6 +276,7 @@ class Editor extends View destroyFold: (foldId) -> @activeEditSession.destroyFold(foldId) destroyFoldsContainingBufferRow: (bufferRow) -> @activeEditSession.destroyFoldsContainingBufferRow(bufferRow) isFoldedAtScreenRow: (screenRow) -> @activeEditSession.isFoldedAtScreenRow(screenRow) + isFoldedAtBufferRow: (bufferRow) -> @activeEditSession.isFoldedAtBufferRow(bufferRow) lineForScreenRow: (screenRow) -> @activeEditSession.lineForScreenRow(screenRow) linesForScreenRows: (start, end) -> @activeEditSession.linesForScreenRows(start, end) diff --git a/src/app/gutter.coffee b/src/app/gutter.coffee index e1e2f8a82..9f7de8f7a 100644 --- a/src/app/gutter.coffee +++ b/src/app/gutter.coffee @@ -58,16 +58,19 @@ class Gutter extends View @renderLineNumbers(renderFrom, renderTo) if performUpdate renderLineNumbers: (startScreenRow, endScreenRow) -> - rows = @editor().bufferRowsForScreenRows(startScreenRow, endScreenRow) + editor = @editor() + rows = editor.bufferRowsForScreenRows(startScreenRow, endScreenRow) - cursorScreenRow = @editor().getCursorScreenPosition().row + cursorScreenRow = editor.getCursorScreenPosition().row @lineNumbers[0].innerHTML = $$$ -> for row in rows if row == lastScreenRow rowValue = '•' else rowValue = row + 1 - @div {class: 'line-number'}, rowValue + classes = ['line-number'] + classes.push('fold') if editor.isFoldedAtBufferRow(row) + @div rowValue, class: classes.join(' ') lastScreenRow = row @calculateWidth() diff --git a/themes/Atom - Dark/editor.css b/themes/Atom - Dark/editor.css index a9a8429d7..64d73ff3b 100644 --- a/themes/Atom - Dark/editor.css +++ b/themes/Atom - Dark/editor.css @@ -43,10 +43,19 @@ -webkit-animation-iteration-count: 1; } -.editor .fold { +.editor .line.fold { background-color: #444; } +.editor .gutter .line-number.fold { + color: #FBA0E3; + opacity: .75; +} + +.editor .gutter .line-number.fold.cursor-line { + opacity: 1; +} + .editor .fold.selected { background-color: #244; } diff --git a/themes/Atom - Light/editor.css b/themes/Atom - Light/editor.css index 9326721b9..ae5837c62 100644 --- a/themes/Atom - Light/editor.css +++ b/themes/Atom - Light/editor.css @@ -46,10 +46,19 @@ -webkit-animation-iteration-count: 1; } -.editor .fold { +.editor .line.fold { background-color: #444; } +.editor .gutter .line-number.fold { + color: #FBA0E3; + opacity: .75; +} + +.editor .gutter .line-number.fold.cursor-line { + opacity: 1; +} + .editor .fold.selected { background-color: #244; } From f90d29262cb786e4a963bb68cb46ae65d6172dd4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 30 Jan 2013 11:49:09 -0800 Subject: [PATCH 33/80] Use octicon as folding indicator --- spec/app/editor-spec.coffee | 5 ++++- src/app/editor.coffee | 4 ++-- themes/Atom - Dark/editor.css | 19 +++++++++++-------- themes/Atom - Light/editor.css | 19 +++++++++++-------- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index 753aa7c85..433a890e7 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -1903,16 +1903,18 @@ describe "Editor", -> editor.attachToDom() describe "when a fold-selection event is triggered", -> - it "folds the lines covered by the selection into a single line with a fold class", -> + it "folds the lines covered by the selection into a single line with a fold class and marker", -> editor.getSelection().setBufferRange(new Range([4, 29], [7, 4])) editor.trigger 'editor:fold-selection' expect(editor.renderedLines.find('.line:eq(4)')).toHaveClass('fold') + expect(editor.renderedLines.find('.line:eq(4) > .fold-marker')).toExist() expect(editor.renderedLines.find('.line:eq(5)').text()).toBe '8' expect(editor.getSelection().isEmpty()).toBeTruthy() expect(editor.getCursorScreenPosition()).toEqual [5, 0] + describe "when a fold placeholder line is clicked", -> it "removes the associated fold and places the cursor at its beginning", -> editor.setCursorBufferPosition([3,0]) @@ -1921,6 +1923,7 @@ describe "Editor", -> editor.find('.fold.line').mousedown() expect(editor.find('.fold')).not.toExist() + expect(editor.find('.fold-marker')).not.toExist() expect(editor.renderedLines.find('.line:eq(4)').text()).toMatch /4-+/ expect(editor.renderedLines.find('.line:eq(5)').text()).toMatch /5/ diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 6daf0f276..79fc4fba0 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -1059,8 +1059,6 @@ class Editor extends View if fold = screenLine.fold lineAttributes = { class: 'fold line', 'fold-id': fold.id } - if @activeEditSession.selectionIntersectsBufferRange(fold.getBufferRange()) - lineAttributes.class += ' selected' else lineAttributes = { class: 'line' } @@ -1093,6 +1091,8 @@ class Editor extends View if invisibles.eol line.push("") + line.push("") if fold + line.push('') line.join('') diff --git a/themes/Atom - Dark/editor.css b/themes/Atom - Dark/editor.css index 64d73ff3b..d15b4a7e0 100644 --- a/themes/Atom - Dark/editor.css +++ b/themes/Atom - Dark/editor.css @@ -43,21 +43,24 @@ -webkit-animation-iteration-count: 1; } -.editor .line.fold { - background-color: #444; -} - .editor .gutter .line-number.fold { - color: #FBA0E3; - opacity: .75; + color: #fba0e3; + opacity: .8; } .editor .gutter .line-number.fold.cursor-line { opacity: 1; } -.editor .fold.selected { - background-color: #244; +.editor .fold-marker:before { + content: '\f25e'; + font-family: 'Octicons Regular'; + display: inline-block; + margin-left: .5em; + margin-top: .1em; + line-height: .8em; + -webkit-font-smoothing: antialiased; + color: #fba0e3; } .editor .invisible { diff --git a/themes/Atom - Light/editor.css b/themes/Atom - Light/editor.css index ae5837c62..14e16fbc5 100644 --- a/themes/Atom - Light/editor.css +++ b/themes/Atom - Light/editor.css @@ -46,21 +46,24 @@ -webkit-animation-iteration-count: 1; } -.editor .line.fold { - background-color: #444; -} - .editor .gutter .line-number.fold { - color: #FBA0E3; - opacity: .75; + color: #fba0e3; + opacity: .8; } .editor .gutter .line-number.fold.cursor-line { opacity: 1; } -.editor .fold.selected { - background-color: #244; +.editor .fold-marker:before { + content: '\f25e'; + font-family: 'Octicons Regular'; + display: inline-block; + margin-left: .5em; + margin-top: .1em; + line-height: .8em; + -webkit-font-smoothing: antialiased; + color: #fba0e3; } .editor .invisible { From 9ea29b2899884fa8be2603a32ad584347535e3c4 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Wed, 30 Jan 2013 10:29:17 -0800 Subject: [PATCH 34/80] Set font-family css property using style tag --- spec/app/editor-spec.coffee | 24 +++++++++++++++++------- src/app/editor.coffee | 11 ++++++++--- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index 2660b14fa..eb7494738 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -518,15 +518,25 @@ describe "Editor", -> describe "font family", -> beforeEach -> - expect(editor.css('font-family')).not.toBe 'monaco' + expect(editor.css('font-family')).not.toBe 'Courier' it "sets the initial font family based on the value from config", -> - config.set("editor.fontFamily", "monaco") - newEditor = editor.splitRight() - expect(editor.css('font-family')).toBe 'monaco' - expect(newEditor.css('font-family')).toBe 'monaco' + expect($("head style.font-family")).toExist() + expect($("head style.font-family").text()).toMatch "{font-family: #{config.get('editor.fontFamily')}}" + + describe "when the font family changes", -> + it "updates the font family on new and existing editors", -> + rootView.attachToDom() + rootView.height(200) + rootView.width(200) + + config.set("editor.fontFamily", "Courier") + newEditor = editor.splitRight() + + expect($("head style.font-family").text()).toMatch "{font-family: Courier}" + expect(editor.css('font-family')).toBe 'Courier' + expect(newEditor.css('font-family')).toBe 'Courier' - describe "when the font family changes on the view", -> it "updates the font family of editors and recalculates dimensions critical to cursor positioning", -> rootView.attachToDom() rootView.height(200) @@ -534,8 +544,8 @@ describe "Editor", -> lineHeightBefore = editor.lineHeight charWidthBefore = editor.charWidth + config.set("editor.fontFamily", "Courier") editor.setCursorScreenPosition [5, 6] - config.set("editor.fontFamily", "monaco") expect(editor.charWidth).not.toBe charWidthBefore expect(editor.getCursorView().position()).toEqual { top: 5 * editor.lineHeight, left: 6 * editor.charWidth } expect(editor.verticalScrollbarContent.height()).toBe buffer.getLineCount() * editor.lineHeight diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 875e4163a..a45e1c636 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -690,9 +690,14 @@ class Editor extends View getFontSize: -> @fontSize setFontFamily: (@fontFamily) -> - if fontFamily? - @css('font-family', fontFamily) - @redraw() + headTag = $("head") + styleTag = headTag.find("style.font-family") + if styleTag.length == 0 + styleTag = $$ -> @style class: 'font-family' + headTag.append styleTag + + styleTag.text(".editor {font-family: #{@fontFamily}}") + @redraw() getFontFamily: -> @fontFamily From 29ccd271de3424e854f201f2a1cf35f83c605cd2 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Wed, 30 Jan 2013 12:11:17 -0800 Subject: [PATCH 35/80] Set font-size css property using style tag --- spec/app/editor-spec.coffee | 25 +++++++++++++++++++------ src/app/editor.coffee | 11 ++++++++--- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index eb7494738..8a9811704 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -551,13 +551,26 @@ describe "Editor", -> expect(editor.verticalScrollbarContent.height()).toBe buffer.getLineCount() * editor.lineHeight describe "font size", -> - it "sets the initial font size based on the value from config", -> - config.set("editor.fontSize", 20) - newEditor = editor.splitRight() - expect(editor.css('font-size')).toBe '20px' - expect(newEditor.css('font-size')).toBe '20px' + beforeEach -> + expect(editor.css('font-size')).not.toBe "20px" + + it "sets the initial font size based on the value from config", -> + expect($("head style.font-size")).toExist() + expect($("head style.font-size").text()).toMatch "{font-size: #{config.get('editor.fontSize')}px}" + + describe "when the font size changes", -> + it "updates the font family on new and existing editors", -> + rootView.attachToDom() + rootView.height(200) + rootView.width(200) + + config.set("editor.fontSize", 20) + newEditor = editor.splitRight() + + expect($("head style.font-size").text()).toMatch "{font-size: 20px}" + expect(editor.css('font-size')).toBe '20px' + expect(newEditor.css('font-size')).toBe '20px' - describe "when the font size changes on the view", -> it "updates the font sizes of editors and recalculates dimensions critical to cursor positioning", -> rootView.attachToDom() rootView.height(200) diff --git a/src/app/editor.coffee b/src/app/editor.coffee index a45e1c636..a4dd22579 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -683,9 +683,14 @@ class Editor extends View @save() if @getPath()? setFontSize: (@fontSize) -> - if fontSize? - @css('font-size', fontSize + 'px') - @redraw() + headTag = $("head") + styleTag = headTag.find("style.font-size") + if styleTag.length == 0 + styleTag = $$ -> @style class: 'font-size' + headTag.append styleTag + + styleTag.text(".editor {font-size: #{@fontSize}px}") + @redraw() getFontSize: -> @fontSize From 9b1cb29e1f693aed0aad3e287bd9631f4ee0ae5c Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Wed, 30 Jan 2013 12:13:20 -0800 Subject: [PATCH 36/80] Don't store fontSize and fontFamily as instance variables --- spec/app/root-view-spec.coffee | 2 +- src/app/editor.coffee | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/spec/app/root-view-spec.coffee b/spec/app/root-view-spec.coffee index 20b5bca36..b046bef30 100644 --- a/spec/app/root-view-spec.coffee +++ b/spec/app/root-view-spec.coffee @@ -567,9 +567,9 @@ describe "RootView", -> editor = null beforeEach -> editor = rootView.getActiveEditor() + editor.attachToDom() it "increases/decreases font size when increase/decrease-font-size events are triggered", -> - editor = rootView.getActiveEditor() fontSizeBefore = editor.getFontSize() rootView.trigger 'window:increase-font-size' expect(editor.getFontSize()).toBe fontSizeBefore + 1 diff --git a/src/app/editor.coffee b/src/app/editor.coffee index a4dd22579..47517e043 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -682,29 +682,30 @@ class Editor extends View autosave: -> @save() if @getPath()? - setFontSize: (@fontSize) -> + setFontSize: (fontSize) -> headTag = $("head") styleTag = headTag.find("style.font-size") if styleTag.length == 0 styleTag = $$ -> @style class: 'font-size' headTag.append styleTag - styleTag.text(".editor {font-size: #{@fontSize}px}") + styleTag.text(".editor {font-size: #{fontSize}px}") @redraw() - getFontSize: -> @fontSize + getFontSize: -> + parseInt(@css("font-size")) - setFontFamily: (@fontFamily) -> + setFontFamily: (fontFamily) -> headTag = $("head") styleTag = headTag.find("style.font-family") if styleTag.length == 0 styleTag = $$ -> @style class: 'font-family' headTag.append styleTag - styleTag.text(".editor {font-family: #{@fontFamily}}") + styleTag.text(".editor {font-family: #{fontFamily}}") @redraw() - getFontFamily: -> @fontFamily + getFontFamily: -> @css("font-family") redraw: -> return unless @attached From 14f761ec37432f03e91a085848f8606b721062ff Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Wed, 30 Jan 2013 12:20:24 -0800 Subject: [PATCH 37/80] =?UTF-8?q?small=20doc=20tweak=E2=80=A6hopefully=20f?= =?UTF-8?q?ixes=20bold=20formatting=20on=20docs=20tab?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/packages/intro.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/packages/intro.md b/docs/packages/intro.md index 4f37c9446..7e4d20bfd 100644 --- a/docs/packages/intro.md +++ b/docs/packages/intro.md @@ -18,9 +18,9 @@ my-package/ index.coffee ``` -**NOTE: NPM behavior is partially implemented until we get a working Node.js +**NOTE:** NPM behavior is partially implemented until we get a working Node.js API built into Atom. The goal is to make Atom packages be a superset of NPM -packages** +packages #### package.json From 74cec989bb558e2d15b229e43971f98dfe2169a7 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Wed, 30 Jan 2013 13:19:09 -0800 Subject: [PATCH 38/80] Use getFontSize() --- src/packages/command-panel/src/command-panel-view.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/command-panel/src/command-panel-view.coffee b/src/packages/command-panel/src/command-panel-view.coffee index 7ccb74a48..d27711a70 100644 --- a/src/packages/command-panel/src/command-panel-view.coffee +++ b/src/packages/command-panel/src/command-panel-view.coffee @@ -51,7 +51,7 @@ class CommandPanelView extends View @previewList.hide() @previewCount.hide() @errorMessages.hide() - @prompt.iconSize(@miniEditor.fontSize) + @prompt.iconSize(@miniEditor.getFontSize()) serialize: -> text: @miniEditor.getText() From 06f64b55725e1020e5e0a30dcec5807ac9c747ad Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 30 Jan 2013 13:23:40 -0800 Subject: [PATCH 39/80] Use rotated locate icon for folded line marker --- themes/Atom - Dark/editor.css | 5 +++-- themes/Atom - Light/editor.css | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/themes/Atom - Dark/editor.css b/themes/Atom - Dark/editor.css index d15b4a7e0..b2daa3586 100644 --- a/themes/Atom - Dark/editor.css +++ b/themes/Atom - Dark/editor.css @@ -53,10 +53,11 @@ } .editor .fold-marker:before { - content: '\f25e'; + content: '\f060'; + -webkit-transform: rotate(90deg); font-family: 'Octicons Regular'; display: inline-block; - margin-left: .5em; + margin-left: .3em; margin-top: .1em; line-height: .8em; -webkit-font-smoothing: antialiased; diff --git a/themes/Atom - Light/editor.css b/themes/Atom - Light/editor.css index 14e16fbc5..26dec9cb1 100644 --- a/themes/Atom - Light/editor.css +++ b/themes/Atom - Light/editor.css @@ -56,10 +56,11 @@ } .editor .fold-marker:before { - content: '\f25e'; + content: '\f060'; + -webkit-transform: rotate(90deg); font-family: 'Octicons Regular'; display: inline-block; - margin-left: .5em; + margin-left: .3em; margin-top: .1em; line-height: .8em; -webkit-font-smoothing: antialiased; From 1acf0b870f3a04e53ac36d4c5b0ee2ca24c37481 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 30 Jan 2013 13:48:36 -0800 Subject: [PATCH 40/80] Support translating points and ranges --- spec/app/point-spec.coffee | 6 ++++++ spec/app/range-spec.coffee | 5 +++++ src/app/edit-session.coffee | 8 ++------ src/app/point.coffee | 4 ++++ src/app/range.coffee | 3 +++ 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/spec/app/point-spec.coffee b/spec/app/point-spec.coffee index 322bac5f2..d4d78715c 100644 --- a/spec/app/point-spec.coffee +++ b/spec/app/point-spec.coffee @@ -25,3 +25,9 @@ describe "Point", -> expect(new Point(5, 0).compare(new Point(6, 1))).toBe -1 expect(new Point(5, 5).compare(new Point(4, 1))).toBe 1 expect(new Point(5, 5).compare(new Point(5, 3))).toBe 1 + + describe ".translate(other)", -> + it "returns a translated point", -> + expect(new Point(1,2).translate([2,4])).toEqual [3,6] + expect(new Point(1,2).translate([-1])).toEqual [0,2] + expect(new Point(1,2).translate([0,-2])).toEqual [1,0] diff --git a/spec/app/range-spec.coffee b/spec/app/range-spec.coffee index 780962a5f..c73111ace 100644 --- a/spec/app/range-spec.coffee +++ b/spec/app/range-spec.coffee @@ -32,3 +32,8 @@ describe "Range", -> expect(new Range([2, 1], [3, 10]).union(new Range([1, 1], [2, 10]))).toEqual [[1, 1], [3, 10]] expect(new Range([2, 1], [3, 10]).union(new Range([2, 5], [3, 1]))).toEqual [[2, 1], [3, 10]] expect(new Range([2, 5], [3, 1]).union(new Range([2, 1], [3, 10]))).toEqual [[2, 1], [3, 10]] + + describe ".translate(startPoint, endPoint)", -> + it "returns a range translates by the specified start and end points", -> + expect(new Range([1, 1], [2, 10]).translate([1])).toEqual [[2, 1], [3, 10]] + expect(new Range([1, 1], [2, 10]).translate([1,2], [3,4])).toEqual [[2, 3], [5, 14]] diff --git a/src/app/edit-session.coffee b/src/app/edit-session.coffee index f0be412a5..c3eaa685a 100644 --- a/src/app/edit-session.coffee +++ b/src/app/edit-session.coffee @@ -369,9 +369,7 @@ class EditSession @foldBufferRow(foldedRow) for foldedRow in foldedRows - newStartPosition = [selection.start.row - 1, selection.start.column] - newEndPosition = [selection.end.row - 1, selection.end.column] - @setSelectedBufferRange([newStartPosition, newEndPosition], preserveFolds: true) + @setSelectedBufferRange(selection.translate([-1]), preserveFolds: true) moveLineDown: -> selection = @getSelectedBufferRange() @@ -408,9 +406,7 @@ class EditSession @foldBufferRow(foldedRow) for foldedRow in foldedRows - newStartPosition = [selection.start.row + 1, selection.start.column] - newEndPosition = [selection.end.row + 1, selection.end.column] - @setSelectedBufferRange([newStartPosition, newEndPosition], preserveFolds: true) + @setSelectedBufferRange(selection.translate([1]), preserveFolds: true) mutateSelectedText: (fn) -> diff --git a/src/app/point.coffee b/src/app/point.coffee index b740027f6..e471ad6c6 100644 --- a/src/app/point.coffee +++ b/src/app/point.coffee @@ -34,6 +34,10 @@ class Point new Point(row, column) + translate: (other) -> + other = Point.fromObject(other) + new Point(@row + other.row, @column + other.column) + splitAt: (column) -> if @row == 0 rightColumn = @column - column diff --git a/src/app/range.coffee b/src/app/range.coffee index 3464a3bce..136f52f15 100644 --- a/src/app/range.coffee +++ b/src/app/range.coffee @@ -48,6 +48,9 @@ class Range add: (point) -> new Range(@start.add(point), @end.add(point)) + translate: (startPoint, endPoint=startPoint) -> + new Range(@start.translate(startPoint), @end.translate(endPoint)) + intersectsWith: (otherRange) -> if @start.isLessThanOrEqual(otherRange.start) @end.isGreaterThanOrEqual(otherRange.start) From 5f343d74b21dd4658d562084eeadcea388ba4ebd Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 30 Jan 2013 13:54:26 -0800 Subject: [PATCH 41/80] Use new EditSession.isFoldedAtBufferRow method when moving lines --- src/app/edit-session.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/edit-session.coffee b/src/app/edit-session.coffee index c3eaa685a..e3a906e8a 100644 --- a/src/app/edit-session.coffee +++ b/src/app/edit-session.coffee @@ -348,7 +348,7 @@ class EditSession foldedRows = [] rows = [selection.start.row..selection.end.row] if selection.start.row isnt selection.end.row and selection.end.column is 0 - rows.pop() unless @isFoldedAtScreenRow(@screenPositionForBufferPosition(selection.end).row) + rows.pop() unless @isFoldedAtBufferRow(selection.end.row) for row in rows screenRow = @screenPositionForBufferPosition([row]).row if @isFoldedAtScreenRow(screenRow) @@ -381,7 +381,7 @@ class EditSession foldedRows = [] rows = [selection.end.row..selection.start.row] if selection.start.row isnt selection.end.row and selection.end.column is 0 - rows.shift() unless @isFoldedAtScreenRow(@screenPositionForBufferPosition(selection.end).row) + rows.shift() unless @isFoldedAtBufferRow(selection.end.row) for row in rows screenRow = @screenPositionForBufferPosition([row]).row if @isFoldedAtScreenRow(screenRow) From 1fa16c4ae125c3c1904cf8a7f23d78aecc837d16 Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Wed, 30 Jan 2013 13:56:35 -0800 Subject: [PATCH 42/80] refocus preview list after performing operation Allows esc key to exit the command pallete --- src/packages/command-panel/src/command-panel-view.coffee | 1 - src/packages/command-panel/src/preview-list.coffee | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/packages/command-panel/src/command-panel-view.coffee b/src/packages/command-panel/src/command-panel-view.coffee index b297516df..7ccb74a48 100644 --- a/src/packages/command-panel/src/command-panel-view.coffee +++ b/src/packages/command-panel/src/command-panel-view.coffee @@ -44,7 +44,6 @@ class CommandPanelView extends View @command 'tool-panel:unfocus', => @rootView.focus() @command 'core:close', => @detach(); false - @command 'core:cancel', => @detach(); false @command 'core:confirm', => @execute() @command 'core:move-up', => @navigateBackwardInHistory() @command 'core:move-down', => @navigateForwardInHistory() diff --git a/src/packages/command-panel/src/preview-list.coffee b/src/packages/command-panel/src/preview-list.coffee index 34cbd240c..a068da3e2 100644 --- a/src/packages/command-panel/src/preview-list.coffee +++ b/src/packages/command-panel/src/preview-list.coffee @@ -83,7 +83,7 @@ class PreviewList extends ScrollView editSession = @rootView.open(operation.getPath()) bufferRange = operation.execute(editSession) editSession.setSelectedBufferRange(bufferRange, autoscroll: true) if bufferRange - @rootView.focus() + @.focus() false getPathCount: -> From ed824469c15301584f479c17471f121ec69b92e8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 30 Jan 2013 14:25:36 -0800 Subject: [PATCH 43/80] Add initial CONTRIBUTING.md Refs #189 --- CONTRIBUTING.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..ac09dc3e8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,20 @@ +# :rotating_light: Contributing to Atom :rotating_light: + +## Issues + * Include screenshots and animated GIFs whenever possible, they are immensely + helpful + * Include the behavior you expected to happen and other places you've seen + that behavior such as Emacs, vi, Xcode, etc. + * Check the Console app for stack traces to include if reporting a crash + * Check the Dev tools (`alt-cmd-i`) for errors and stack traces to include + +## Code + * Follow the [JavaScript](https://github.com/styleguide/javascript), + [CSS](https://github.com/styleguide/css), + and [Objective-C](https://github.com/github/objective-c-conventions) + styleguides + * Include thoughtfully worded [Jasmine](http://pivotal.github.com/jasmine/) + specs + * New packages go in `src/packages/` + * Add 3rd-party packages by submoduling in `vendor/packages/` + * Commit messages are in the present tense From d30532c6aacf4f46bb6282890468260f8fc1ec22 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 30 Jan 2013 15:05:36 -0800 Subject: [PATCH 44/80] Show directory in tab when duplicate names are open Closes #181 --- src/packages/tabs/spec/tabs-spec.coffee | 18 ++++++++++++++++++ src/packages/tabs/src/tab.coffee | 16 ++++++++++++++-- src/packages/tabs/src/tabs-view.coffee | 2 +- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/packages/tabs/spec/tabs-spec.coffee b/src/packages/tabs/spec/tabs-spec.coffee index c3055d081..76558b301 100644 --- a/src/packages/tabs/spec/tabs-spec.coffee +++ b/src/packages/tabs/spec/tabs-spec.coffee @@ -118,3 +118,21 @@ describe "Tabs", -> tabs.find('.tab .close-icon:eq(1)').click() expect(editor.getActiveEditSessionIndex()).toBe 0 expect(editor.activeEditSession).toBe firstSession + + describe "when two tabs have the same file name", -> + [tempPath] = [] + + beforeEach -> + tempPath = '/tmp/sample.js' + fs.write(tempPath, 'sample') + + afterEach -> + fs.remove(tempPath) if fs.exists(tempPath) + + it "displays the parent folder name after the file name", -> + expect(tabs.find('.tab:eq(0) .file-name').text()).toBe 'sample.js' + rootView.open(tempPath) + expect(tabs.find('.tab:eq(0) .file-name').text()).toBe 'sample.js - fixtures' + expect(tabs.find('.tab:last .file-name').text()).toBe 'sample.js - tmp' + editor.destroyActiveEditSession() + expect(tabs.find('.tab:eq(0) .file-name').text()).toBe 'sample.js' diff --git a/src/packages/tabs/src/tab.coffee b/src/packages/tabs/src/tab.coffee index 6a26a114f..7bc1a8828 100644 --- a/src/packages/tabs/src/tab.coffee +++ b/src/packages/tabs/src/tab.coffee @@ -1,4 +1,5 @@ {View} = require 'space-pen' +fs = require 'fs' module.exports = class Tab extends View @@ -7,12 +8,14 @@ class Tab extends View @span class: 'file-name', outlet: 'fileName' @span class: 'close-icon' - initialize: (@editSession) -> + initialize: (@editSession, @editor) -> @buffer = @editSession.buffer @subscribe @buffer, 'path-changed', => @updateFileName() @subscribe @buffer, 'contents-modified', => @updateModifiedStatus() @subscribe @buffer, 'saved', => @updateModifiedStatus() @subscribe @buffer, 'git-status-changed', => @updateModifiedStatus() + @subscribe @editor, 'editor:edit-session-added', => @updateFileName() + @subscribe @editor, 'editor:edit-session-removed', => @updateFileName() @updateFileName() @updateModifiedStatus() @@ -25,4 +28,13 @@ class Tab extends View @isModified = false updateFileName: -> - @fileName.text(@editSession.buffer.getBaseName() ? 'untitled') + fileNameText = @editSession.buffer.getBaseName() + if fileNameText? + duplicates = @editor.getEditSessions().filter (session) -> fileNameText is session.buffer.getBaseName() + if duplicates.length > 1 + directory = fs.base(fs.directory(@editSession.getPath())) + fileNameText = "#{fileNameText} - #{directory}" if directory + else + fileNameText = 'untitled' + + @fileName.text(fileNameText) diff --git a/src/packages/tabs/src/tabs-view.coffee b/src/packages/tabs/src/tabs-view.coffee index e7322dc64..d2b21fa7c 100644 --- a/src/packages/tabs/src/tabs-view.coffee +++ b/src/packages/tabs/src/tabs-view.coffee @@ -34,7 +34,7 @@ class Tabs extends View false addTabForEditSession: (editSession) -> - @append(new Tab(editSession)) + @append(new Tab(editSession, @editor)) setActiveTab: (index) -> @find(".tab.active").removeClass('active') From 034281a6388fee9f94ac1b83d9bdc43df992f417 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 30 Jan 2013 15:06:57 -0800 Subject: [PATCH 45/80] :lipstick: --- src/packages/tabs/spec/tabs-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/tabs/spec/tabs-spec.coffee b/src/packages/tabs/spec/tabs-spec.coffee index 76558b301..c36922a38 100644 --- a/src/packages/tabs/spec/tabs-spec.coffee +++ b/src/packages/tabs/spec/tabs-spec.coffee @@ -5,7 +5,7 @@ Tabs = require 'tabs' fs = require 'fs' describe "Tabs", -> - [rootView, editor, statusBar, buffer, tabs] = [] + [rootView, editor, buffer, tabs] = [] beforeEach -> rootView = new RootView(require.resolve('fixtures/sample.js')) From 8b3ade290406ee4881bc3aeb95acb1906f86766d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 30 Jan 2013 15:08:23 -0800 Subject: [PATCH 46/80] Set path as tab title attribute --- src/packages/tabs/src/tab.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/packages/tabs/src/tab.coffee b/src/packages/tabs/src/tab.coffee index 7bc1a8828..6a8ba4338 100644 --- a/src/packages/tabs/src/tab.coffee +++ b/src/packages/tabs/src/tab.coffee @@ -38,3 +38,4 @@ class Tab extends View fileNameText = 'untitled' @fileName.text(fileNameText) + @fileName.attr('title', @editSession.getPath()) From 45d5e714fa43788cca4aa86a93daca02d9dfb0d9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 30 Jan 2013 15:25:03 -0800 Subject: [PATCH 47/80] Make snippets keymaps valid CSON Closes #209 --- src/packages/snippets/keymaps/snippets-1.cson | 2 +- src/packages/snippets/keymaps/snippets-2.cson | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/packages/snippets/keymaps/snippets-1.cson b/src/packages/snippets/keymaps/snippets-1.cson index c8bf63c51..ce982b6a2 100644 --- a/src/packages/snippets/keymaps/snippets-1.cson +++ b/src/packages/snippets/keymaps/snippets-1.cson @@ -1,2 +1,2 @@ -window.keymap.bindKeys '.editor' +'.editor': 'tab': 'snippets:expand' diff --git a/src/packages/snippets/keymaps/snippets-2.cson b/src/packages/snippets/keymaps/snippets-2.cson index 6b660c6fd..9cf7b49e5 100644 --- a/src/packages/snippets/keymaps/snippets-2.cson +++ b/src/packages/snippets/keymaps/snippets-2.cson @@ -1,6 +1,6 @@ # it's critical that these bindings be loaded after those snippets-1 so they # are later in the cascade, hence breaking the keymap into 2 files -window.keymap.bindKeys '.editor' +'.editor': 'tab': 'snippets:next-tab-stop' 'shift-tab': 'snippets:previous-tab-stop' From 79d569d55b5f635785032f9f44ab57b93cd76846 Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Wed, 30 Jan 2013 15:30:10 -0800 Subject: [PATCH 48/80] rename atom.coffee to user.coffee --- .atom/{atom.coffee => user.coffee} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .atom/{atom.coffee => user.coffee} (100%) diff --git a/.atom/atom.coffee b/.atom/user.coffee similarity index 100% rename from .atom/atom.coffee rename to .atom/user.coffee From 0233b4a53eecff7bfe96aeb6cea2b914b178e230 Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Wed, 30 Jan 2013 15:30:18 -0800 Subject: [PATCH 49/80] add .atom/user.css file --- .atom/user.css | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .atom/user.css diff --git a/.atom/user.css b/.atom/user.css new file mode 100644 index 000000000..f53057581 --- /dev/null +++ b/.atom/user.css @@ -0,0 +1,8 @@ +// User styles +.tree-view { + +} + +.editor { + +} \ No newline at end of file From 228c9ff5225467331053ee782bf3838592f20410 Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Wed, 30 Jan 2013 15:33:52 -0800 Subject: [PATCH 50/80] update readme to point to user.coffee instead of atom.coffee --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f6e23611e..04459faa3 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Requirements Atom is installed! Type `atom [path]` from the commmand line or find it in `/Applications/Atom.app` ## Your ~/.atom Directory -A basic ~/.atom directory is installed when you run `rake install`. Take a look at ~/.atom/atom.coffee for more information. +A basic ~/.atom directory is installed when you run `rake install`. Take a look at ~/.atom/user.coffee for more information. ## Basic Keyboard shortcuts Atom doesn't have much in the way of menus yet. Use these keyboard shortcuts to @@ -53,7 +53,7 @@ Most default OS X keybindings also work. ## Init Script -Atom will require `~/.atom/atom.coffee` whenever a window is opened or reloaded if it is present in your +Atom will require `~/.atom/user.coffee` whenever a window is opened or reloaded if it is present in your home directory. This is a rudimentary jumping off point for your own customizations. ## Command Panel From 389ecc0b4ae807bc94e7bd5072f40aefda7be249 Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Wed, 30 Jan 2013 15:34:26 -0800 Subject: [PATCH 51/80] copy over user.coffee in rake task --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index e6adbba94..bd693df3f 100644 --- a/Rakefile +++ b/Rakefile @@ -80,7 +80,7 @@ task "create-dot-atom" do `rm -rf "#{DOT_ATOM_PATH}"` `mkdir "#{DOT_ATOM_PATH}"` - `cp "#{dot_atom_template_path}/atom.coffee" "#{DOT_ATOM_PATH}"` + `cp "#{dot_atom_template_path}/user.coffee" "#{DOT_ATOM_PATH}"` `cp "#{dot_atom_template_path}/packages" "#{DOT_ATOM_PATH}"` `cp -r "#{ATOM_SRC_PATH}/themes" "#{DOT_ATOM_PATH}"` `cp "#{ATOM_SRC_PATH}/vendor/themes/IR_Black.tmTheme" "#{DOT_ATOM_PATH}/themes"` From 82f1fb44200f8f109d4adf057878ebe5f2e548b4 Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Wed, 30 Jan 2013 15:34:38 -0800 Subject: [PATCH 52/80] load user.coffee from .atom directory --- src/app/config.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/config.coffee b/src/app/config.coffee index bf35eff63..26efbd674 100644 --- a/src/app/config.coffee +++ b/src/app/config.coffee @@ -4,7 +4,7 @@ EventEmitter = require 'event-emitter' configDirPath = fs.absolute("~/.atom") configJsonPath = fs.join(configDirPath, "config.json") -userInitScriptPath = fs.join(configDirPath, "atom.coffee") +userInitScriptPath = fs.join(configDirPath, "user.coffee") bundledPackagesDirPath = fs.join(resourcePath, "src/packages") bundledThemesDirPath = fs.join(resourcePath, "themes") vendoredPackagesDirPath = fs.join(resourcePath, "vendor/packages") From aeb1e3fd3ccdb91f0896fa55e18145875d1bd7c9 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 30 Jan 2013 16:53:36 -0700 Subject: [PATCH 53/80] Add a script to fix the author w/ git-filter-branch --- script/fix-author | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100755 script/fix-author diff --git a/script/fix-author b/script/fix-author new file mode 100755 index 000000000..bbbd3b3da --- /dev/null +++ b/script/fix-author @@ -0,0 +1,17 @@ +#!/bin/sh + +usage() { + echo "usage: $0 sha name email" + exit 1 +} + +if [ ! $3 ]; then + usage +fi + +git filter-branch -f --env-filter " +export GIT_AUTHOR_NAME='$2' +export GIT_AUTHOR_EMAIL='$3' +export GIT_COMMITTER_NAME='$2' +export GIT_COMMITTER_EMAIL='$3' +" -- $1..HEAD \ No newline at end of file From 95d7c89ec52dab8cf677ff0bf46b0e3d7839b41b Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Wed, 30 Jan 2013 16:00:45 -0800 Subject: [PATCH 54/80] load styles from ~/.atom/user.css --- src/app/atom.coffee | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/app/atom.coffee b/src/app/atom.coffee index 455382926..43c4d942d 100644 --- a/src/app/atom.coffee +++ b/src/app/atom.coffee @@ -7,6 +7,8 @@ LoadTextMatePackagesTask = require 'load-text-mate-packages-task' messageIdCounter = 1 originalSendMessageToBrowserProcess = atom.sendMessageToBrowserProcess +configDirPath = fs.absolute("~/.atom") +userStylePath = fs.join(configDirPath, "user.css") _.extend atom, exitWhenDone: window.location.params.exitWhenDone @@ -53,10 +55,15 @@ _.extend atom, themeNames = config.get("core.themes") ? ['Atom - Dark', 'IR_Black'] themeNames = [themeNames] unless _.isArray(themeNames) @loadTheme(themeName) for themeName in themeNames + @loadUserStyles() loadTheme: (name) -> @loadedThemes.push Theme.load(name) + loadUserStyles: -> + if fs.exists(userStylePath) + applyStylesheet(userStylePath, fs.read(userStylePath), 'userTheme') + getAtomThemeStylesheets: -> themeNames = config.get("core.themes") ? ['Atom - Dark', 'IR_Black'] themeNames = [themeNames] unless _.isArray(themeNames) From 4e7b1888b4789b03e79fb18b0eb08cf26c0c7811 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Wed, 30 Jan 2013 16:03:55 -0800 Subject: [PATCH 55/80] include ' in editor.nonWordCharacters --- src/app/editor.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 2234ece09..2769b6cba 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -20,7 +20,7 @@ class Editor extends View autosave: false autoIndent: true autoIndentOnPaste: false - nonWordCharacters: "./\\()\"’-_:,.;<>~!@#$%^&*|+=[]{}`~?" + nonWordCharacters: "./\\()\"'-_:,.;<>~!@#$%^&*|+=[]{}`~?" @content: (params) -> @div class: @classes(params), tabindex: -1, => From 45dfea055943ab025527ae63b5d452e3f672ff60 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 30 Jan 2013 16:12:14 -0800 Subject: [PATCH 56/80] Start tracking commands when package is activated When the command logger was moved to a deferred package the custom trigger to track events wasn't registered until the instance was created causing most events to go untracked. Now the custom trigger is registered in the index.coffee file and passed to the view instance when toggling. --- src/packages/command-logger/index.coffee | 24 ++++++++++++++++++- .../src/command-logger-view.coffee | 24 +++---------------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/packages/command-logger/index.coffee b/src/packages/command-logger/index.coffee index 39dd9ad68..027035980 100644 --- a/src/packages/command-logger/index.coffee +++ b/src/packages/command-logger/index.coffee @@ -1,4 +1,5 @@ DeferredAtomPackage = require 'deferred-atom-package' +$ = require 'jquery' module.exports = class CommandLogger extends DeferredAtomPackage @@ -7,4 +8,25 @@ class CommandLogger extends DeferredAtomPackage instanceClass: 'command-logger/src/command-logger-view' - onLoadEvent: (event, instance) -> instance.toggle() + activate: (rootView, state={})-> + super + + @eventLog = state.eventLog ? {} + rootView.command 'command-logger:clear-data', => @eventLog = {} + + registerTriggeredEvent = (eventName) => + eventNameLog = @eventLog[eventName] + unless eventNameLog + eventNameLog = + count: 0 + name: eventName + @eventLog[eventName] = eventNameLog + eventNameLog.count++ + eventNameLog.lastRun = new Date().getTime() + originalTrigger = $.fn.trigger + $.fn.trigger = (eventName) -> + eventName = eventName.type if eventName.type + registerTriggeredEvent(eventName) if $(this).events()[eventName] + originalTrigger.apply(this, arguments) + + onLoadEvent: (event, instance) -> instance.toggle(@eventLog) diff --git a/src/packages/command-logger/src/command-logger-view.coffee b/src/packages/command-logger/src/command-logger-view.coffee index 01496a2d0..4a5f89df5 100644 --- a/src/packages/command-logger/src/command-logger-view.coffee +++ b/src/packages/command-logger/src/command-logger-view.coffee @@ -1,12 +1,11 @@ {$$$} = require 'space-pen' ScrollView = require 'scroll-view' -$ = require 'jquery' _ = require 'underscore' module.exports = class CommandLoggerView extends ScrollView @activate: (rootView, state) -> - @instance = new CommandLoggerView(rootView, state?.eventLog) + @instance = new CommandLoggerView(rootView) @content: (rootView) -> @div class: 'command-logger', tabindex: -1, => @@ -31,29 +30,12 @@ class CommandLoggerView extends ScrollView 'tree-view:directory-modified' ] - initialize: (@rootView, @eventLog={}) -> + initialize: (@rootView) -> super - @rootView.command 'command-logger:clear-data', => @eventLog = {} @command 'core:cancel', => @detach() - registerEvent = (eventName) => - eventNameLog = @eventLog[eventName] - unless eventNameLog - eventNameLog = - count: 0 - name: eventName - @eventLog[eventName] = eventNameLog - eventNameLog.count++ - eventNameLog.lastRun = new Date().getTime() - - originalTrigger = $.fn.trigger - $.fn.trigger = (eventName) -> - eventName = eventName.type if eventName.type - registerEvent(eventName) if $(this).events()[eventName] - originalTrigger.apply(this, arguments) - - toggle: -> + toggle: (@eventLog={}) -> if @hasParent() @detach() else From 9a2db263932a238bc6ded6e79cd656c2a0c54093 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 30 Jan 2013 17:54:16 -0800 Subject: [PATCH 57/80] Set white-space property to nowrap on editor lines Allows inline-block elements adding to the line to no be wrapped when the window is resized. Closes #211 --- static/editor.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/static/editor.css b/static/editor.css index 0b8cfb452..66d71d345 100644 --- a/static/editor.css +++ b/static/editor.css @@ -104,3 +104,7 @@ pointer-events: none; z-index: -1; } + +.editor .line { + white-space: nowrap; +} From 7e030b09e7a7da933b6f4931e73a40ae619b6a17 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Wed, 30 Jan 2013 21:40:26 -0500 Subject: [PATCH 58/80] Adding a line-height to the editor. --- themes/Atom - Dark/editor.css | 1 + themes/Atom - Light/editor.css | 1 + 2 files changed, 2 insertions(+) diff --git a/themes/Atom - Dark/editor.css b/themes/Atom - Dark/editor.css index b2daa3586..533dca1b5 100644 --- a/themes/Atom - Dark/editor.css +++ b/themes/Atom - Dark/editor.css @@ -1,5 +1,6 @@ .editor { font-family: Inconsolata, Monaco, Courier; + line-height: 1.3; } .editor.mini { diff --git a/themes/Atom - Light/editor.css b/themes/Atom - Light/editor.css index 26dec9cb1..ac4a98014 100644 --- a/themes/Atom - Light/editor.css +++ b/themes/Atom - Light/editor.css @@ -1,5 +1,6 @@ .editor { font-family: Inconsolata, Monaco, Courier; + line-height: 1.3; } .editor.mini { From 983f1ab18b08cd226e7dd29b6b048347cb7f80ea Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 30 Jan 2013 18:32:08 -0800 Subject: [PATCH 59/80] Bind meta-~ to focus previous window Closes #212 --- native/atom_cef_client.cpp | 2 ++ native/atom_cef_client.h | 1 + native/atom_cef_client_mac.mm | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/native/atom_cef_client.cpp b/native/atom_cef_client.cpp index 38c25470b..3acb53951 100644 --- a/native/atom_cef_client.cpp +++ b/native/atom_cef_client.cpp @@ -141,6 +141,8 @@ bool AtomCefClient::OnKeyEvent(CefRefPtr browser, ToggleDevTools(browser); } else if (event.modifiers == EVENTFLAG_COMMAND_DOWN && event.unmodified_character == '`') { FocusNextWindow(); + } else if (event.modifiers == (EVENTFLAG_COMMAND_DOWN | EVENTFLAG_SHIFT_DOWN) && event.unmodified_character == '~') { + FocusPreviousWindow(); } else { return false; diff --git a/native/atom_cef_client.h b/native/atom_cef_client.h index 75b787138..d1961d8d3 100644 --- a/native/atom_cef_client.h +++ b/native/atom_cef_client.h @@ -105,6 +105,7 @@ class AtomCefClient : public CefClient, bool m_HandlePasteboardCommands = false; void FocusNextWindow(); + void FocusPreviousWindow(); void Open(std::string path); void Open(); void OpenUnstable(std::string path); diff --git a/native/atom_cef_client_mac.mm b/native/atom_cef_client_mac.mm index c20bd5fbe..be4879d97 100644 --- a/native/atom_cef_client_mac.mm +++ b/native/atom_cef_client_mac.mm @@ -23,6 +23,24 @@ void AtomCefClient::FocusNextWindow() { } } +void AtomCefClient::FocusPreviousWindow() { + NSArray *windows = [NSApp windows]; + int count = [windows count]; + int start = [windows indexOfObject:[NSApp keyWindow]]; + + int i = start; + while (true) { + i = i - 1; + if (i == 0) i = count -1; + if (i == start) break; + NSWindow *window = [windows objectAtIndex:i]; + if ([window isVisible] && ![window isExcludedFromWindowsMenu]) { + [window makeKeyAndOrderFront:nil]; + break; + } + } +} + void AtomCefClient::Open(std::string path) { NSString *pathString = [NSString stringWithCString:path.c_str() encoding:NSUTF8StringEncoding]; [(AtomApplication *)[AtomApplication sharedApplication] open:pathString]; From f126f589210a5e6e359efa1ff9e74395a7f670fb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 30 Jan 2013 19:18:10 -0800 Subject: [PATCH 60/80] Revert "Set white-space property to nowrap on editor lines" This reverts commit 9a2db263932a238bc6ded6e79cd656c2a0c54093. --- static/editor.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/static/editor.css b/static/editor.css index 66d71d345..0b8cfb452 100644 --- a/static/editor.css +++ b/static/editor.css @@ -104,7 +104,3 @@ pointer-events: none; z-index: -1; } - -.editor .line { - white-space: nowrap; -} From 11c0637220472f8cadcaf0b0d7653a7ccaad0d71 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Thu, 31 Jan 2013 10:19:41 -0500 Subject: [PATCH 61/80] Not adding a font family when the user doesn't have it set --- spec/app/editor-spec.coffee | 7 +++---- src/app/editor.coffee | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index 2cbc0cc34..2729be262 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -520,9 +520,8 @@ describe "Editor", -> beforeEach -> expect(editor.css('font-family')).not.toBe 'Courier' - it "sets the initial font family based on the value from config", -> - expect($("head style.font-family")).toExist() - expect($("head style.font-family").text()).toMatch "{font-family: #{config.get('editor.fontFamily')}}" + it "when there is no config in fontFamily don't set it", -> + expect($("head style.font-family")).not.toExist() describe "when the font family changes", -> it "updates the font family on new and existing editors", -> @@ -544,7 +543,7 @@ describe "Editor", -> lineHeightBefore = editor.lineHeight charWidthBefore = editor.charWidth - config.set("editor.fontFamily", "Courier") + config.set("editor.fontFamily", "Inconsolata") editor.setCursorScreenPosition [5, 6] expect(editor.charWidth).not.toBe charWidthBefore expect(editor.getCursorView().position()).toEqual { top: 5 * editor.lineHeight, left: 6 * editor.charWidth } diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 2769b6cba..e9a197158 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -14,7 +14,6 @@ _ = require 'underscore' module.exports = class Editor extends View @configDefaults: - fontFamily: "Inconsolata, Monaco, Courier" fontSize: 20 showInvisibles: false autosave: false @@ -697,6 +696,7 @@ class Editor extends View parseInt(@css("font-size")) setFontFamily: (fontFamily) -> + return if fontFamily == undefined headTag = $("head") styleTag = headTag.find("style.font-family") if styleTag.length == 0 From 4f8181969ed873f134a07259d4448624a1ef7f9e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 31 Jan 2013 09:24:59 -0800 Subject: [PATCH 62/80] :lipstick: --- static/editor.css | 1 - 1 file changed, 1 deletion(-) diff --git a/static/editor.css b/static/editor.css index 0b8cfb452..40c3d1b4e 100644 --- a/static/editor.css +++ b/static/editor.css @@ -56,7 +56,6 @@ overflow-x: hidden; } - .editor .underlayer, .editor .lines, .editor .overlayer { width: 100%; height: 100%; From ef6e525674def664631bf58af6e3ceafd192ef8e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 31 Jan 2013 09:32:20 -0800 Subject: [PATCH 63/80] Use package instead of package's view in specs Event logs are now stored on the package and passed to the view when toggled. --- .../command-logger/spec/command-logger-spec.coffee | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/packages/command-logger/spec/command-logger-spec.coffee b/src/packages/command-logger/spec/command-logger-spec.coffee index c01f24320..e2a06da2b 100644 --- a/src/packages/command-logger/spec/command-logger-spec.coffee +++ b/src/packages/command-logger/spec/command-logger-spec.coffee @@ -6,9 +6,8 @@ describe "CommandLogger", -> beforeEach -> rootView = new RootView(require.resolve('fixtures/sample.js')) - atom.loadPackage('command-logger').getInstance() + commandLogger = atom.loadPackage('command-logger') editor = rootView.getActiveEditor() - commandLogger = CommandLogger.instance afterEach -> rootView.deactivate() @@ -44,9 +43,11 @@ describe "CommandLogger", -> describe "when an event is ignored", -> it "does not create a node for that event", -> - commandLogger.ignoredEvents.push 'editor:delete-line' + commandLoggerView = commandLogger.getInstance() + commandLoggerView.ignoredEvents.push 'editor:delete-line' editor.trigger 'editor:delete-line' - nodes = commandLogger.createNodes() + commandLoggerView.eventLog = commandLogger.eventLog + nodes = commandLoggerView.createNodes() for node in nodes continue unless node.name is 'Editor' for child in node.children From e5bd097592aa7c5987d341ceb678f7b78c354e6b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 31 Jan 2013 09:41:40 -0800 Subject: [PATCH 64/80] Use configDirPath exposed by global config object --- src/app/atom.coffee | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/app/atom.coffee b/src/app/atom.coffee index 43c4d942d..4630eb6fc 100644 --- a/src/app/atom.coffee +++ b/src/app/atom.coffee @@ -7,8 +7,6 @@ LoadTextMatePackagesTask = require 'load-text-mate-packages-task' messageIdCounter = 1 originalSendMessageToBrowserProcess = atom.sendMessageToBrowserProcess -configDirPath = fs.absolute("~/.atom") -userStylePath = fs.join(configDirPath, "user.css") _.extend atom, exitWhenDone: window.location.params.exitWhenDone @@ -55,14 +53,15 @@ _.extend atom, themeNames = config.get("core.themes") ? ['Atom - Dark', 'IR_Black'] themeNames = [themeNames] unless _.isArray(themeNames) @loadTheme(themeName) for themeName in themeNames - @loadUserStyles() + @loadUserStylesheet() loadTheme: (name) -> @loadedThemes.push Theme.load(name) - loadUserStyles: -> - if fs.exists(userStylePath) - applyStylesheet(userStylePath, fs.read(userStylePath), 'userTheme') + loadUserStylesheet: -> + userStylesheetPath = fs.join(config.configDirPath, 'user.css') + if fs.isFile(userStylesheetPath) + applyStylesheet(userStylesheetPath, fs.read(userStylesheetPath), 'userTheme') getAtomThemeStylesheets: -> themeNames = config.get("core.themes") ? ['Atom - Dark', 'IR_Black'] From 30103b66fcefd45ab6050983d5c61794558b3557 Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Thu, 31 Jan 2013 10:18:25 -0800 Subject: [PATCH 65/80] move old atom.coffee to user.coffee on rake install if it exists --- Rakefile | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index bd693df3f..01db92806 100644 --- a/Rakefile +++ b/Rakefile @@ -76,11 +76,24 @@ task "create-dot-atom" do dot_atom_template_path = ATOM_SRC_PATH + "/.atom" replace_dot_atom = false - next if File.exists?(DOT_ATOM_PATH) + + if File.exists?(DOT_ATOM_PATH) + user_config = "#{DOT_ATOM_PATH}/user.coffee" + old_user_config = "#{DOT_ATOM_PATH}/atom.coffee" + + if File.exists?(old_user_config) + `mv #{old_user_config} #{user_config}` + puts "\033[32mRenamed #{old_user_config} to #{user_config}\033[0m" + end + + next + end `rm -rf "#{DOT_ATOM_PATH}"` `mkdir "#{DOT_ATOM_PATH}"` + `cp "#{dot_atom_template_path}/user.coffee" "#{DOT_ATOM_PATH}"` + `cp "#{dot_atom_template_path}/user.css" "#{DOT_ATOM_PATH}"` `cp "#{dot_atom_template_path}/packages" "#{DOT_ATOM_PATH}"` `cp -r "#{ATOM_SRC_PATH}/themes" "#{DOT_ATOM_PATH}"` `cp "#{ATOM_SRC_PATH}/vendor/themes/IR_Black.tmTheme" "#{DOT_ATOM_PATH}/themes"` From 2982c5e51a304ca91f9efb8c12a0ffd895555ea7 Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Thu, 31 Jan 2013 10:22:36 -0800 Subject: [PATCH 66/80] need -r when copying packages directory --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 01db92806..2a14471ac 100644 --- a/Rakefile +++ b/Rakefile @@ -94,7 +94,7 @@ task "create-dot-atom" do `cp "#{dot_atom_template_path}/user.coffee" "#{DOT_ATOM_PATH}"` `cp "#{dot_atom_template_path}/user.css" "#{DOT_ATOM_PATH}"` - `cp "#{dot_atom_template_path}/packages" "#{DOT_ATOM_PATH}"` + `cp -r "#{dot_atom_template_path}/packages" "#{DOT_ATOM_PATH}"` `cp -r "#{ATOM_SRC_PATH}/themes" "#{DOT_ATOM_PATH}"` `cp "#{ATOM_SRC_PATH}/vendor/themes/IR_Black.tmTheme" "#{DOT_ATOM_PATH}/themes"` end From 8f030cd97e9ff83519b3692c3bb4150c31721910 Mon Sep 17 00:00:00 2001 From: Corey Johnson & Kevin Sawicki Date: Thu, 31 Jan 2013 10:31:13 -0800 Subject: [PATCH 67/80] Always calculate dimensions with editor on DOM Closes #206 --- spec/app/editor-spec.coffee | 18 ++++++++++++++++++ src/app/editor.coffee | 6 ++++++ src/stdlib/jquery-extensions.coffee | 3 +++ 3 files changed, 27 insertions(+) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index 2729be262..dee1224d0 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -552,6 +552,7 @@ describe "Editor", -> describe "font size", -> beforeEach -> expect(editor.css('font-size')).not.toBe "20px" + expect(editor.css('font-size')).not.toBe "10px" it "sets the initial font size based on the value from config", -> expect($("head style.font-size")).toExist() @@ -614,6 +615,23 @@ describe "Editor", -> config.set("editor.fontSize", 10) expect(editor.renderedLines.find(".line").length).toBeGreaterThan originalLineCount + describe "when the editor is detached", -> + it "updates the font-size correctly and recalculates the dimensions by placing the rendered lines on the DOM", -> + rootView.attachToDom() + rootView.height(200) + rootView.width(200) + + newEditor = editor.splitRight() + newEditorParent = newEditor.parent() + newEditor.detach() + config.set("editor.fontSize", 10) + newEditorParent.append(newEditor) + + expect(newEditor.lineHeight).toBe editor.lineHeight + expect(newEditor.charWidth).toBe editor.charWidth + expect(newEditor.getCursorView().position()).toEqual editor.getCursorView().position() + expect(newEditor.verticalScrollbarContent.height()).toBe editor.verticalScrollbarContent.height() + describe "mouse events", -> beforeEach -> editor.attachToDom() diff --git a/src/app/editor.coffee b/src/app/editor.coffee index e9a197158..01b8ac40f 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -804,6 +804,10 @@ class Editor extends View @overlayer.append(view) calculateDimensions: -> + if not @isOnDom() + detachedEditorParent = _.last(@parents()) ? this + $(document.body).append(detachedEditorParent) + fragment = $('