From 53bf6f5341b6da6f83c838325ad437b83d238e1a Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Mon, 4 Feb 2013 15:55:14 -0800 Subject: [PATCH 01/32] tag blurred state instead of focused state --- src/app/editor.coffee | 2 -- src/app/window.coffee | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 161e7505e..7d6dcb054 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -351,11 +351,9 @@ class Editor extends View @hiddenInput.on 'focus', => @rootView()?.editorFocused(this) @isFocused = true - @addClass 'is-focused' @hiddenInput.on 'focusout', => @isFocused = false - @removeClass 'is-focused' @autosave() if config.get "editor.autosave" @underlayer.on 'click', (e) => diff --git a/src/app/window.coffee b/src/app/window.coffee index 998f381a4..5158c77d6 100644 --- a/src/app/window.coffee +++ b/src/app/window.coffee @@ -28,8 +28,8 @@ windowAdditions = $(window).on 'core:close', => @close() $(window).command 'window:close', => @close() - $(window).on 'focus', => $("body").addClass("is-focused") - $(window).on 'blur', => $("body").removeClass("is-focused") + $(window).on 'focus', -> $("body").removeClass('is-blurred') + $(window).on 'blur', -> $("body").addClass('is-blurred') # This method is intended only to be run when starting a normal application # Note: RootView assigns itself on window on initialization so that From 4350be62c66358b9564dde117253fea104457698 Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Mon, 4 Feb 2013 16:02:09 -0800 Subject: [PATCH 02/32] :skull: is-focused. targeting blurred state instead so normal state styles don't need a special prefix --- docs/styling.md | 6 +++--- spec/app/editor-spec.coffee | 2 -- spec/app/text-mate-theme-spec.coffee | 4 ++-- spec/app/window-spec.coffee | 8 ++++---- static/editor.css | 4 ++-- themes/atom-dark-syntax.css | 6 +++--- 6 files changed, 14 insertions(+), 16 deletions(-) diff --git a/docs/styling.md b/docs/styling.md index 847df3fbb..47a3795ae 100644 --- a/docs/styling.md +++ b/docs/styling.md @@ -9,8 +9,8 @@ gutter. You can change the background color using the following CSS: ```css -.editor.is-focused .line.cursor-line, -.editor.is-focused .line-number.cursor-line { +.editor .line.cursor-line, +.editor .line-number.cursor-line { background-color: green; } ``` @@ -18,7 +18,7 @@ You can change the background color using the following CSS: You can change the line number foreground color using the following CSS: ```css -.editor.is-focused .line-number.cursor-line { +.editor .line-number.cursor-line { color: blue; } ``` diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index a3ddcf500..cf4524393 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -111,11 +111,9 @@ describe "Editor", -> editor.isFocused = false editor.hiddenInput.focus() expect(editor.isFocused).toBeTruthy() - expect(editor).toHaveClass('is-focused') editor.hiddenInput.focusout() expect(editor.isFocused).toBeFalsy() - expect(editor).not.toHaveClass('is-focused') describe "when the activeEditSession's file is modified on disk", -> it "triggers an alert", -> diff --git a/spec/app/text-mate-theme-spec.coffee b/spec/app/text-mate-theme-spec.coffee index b2f6e54fe..4ed7b84e2 100644 --- a/spec/app/text-mate-theme-spec.coffee +++ b/spec/app/text-mate-theme-spec.coffee @@ -27,12 +27,12 @@ describe "TextMateTheme", -> 'color': '#F8F8F8' expect(rulesets[1]).toEqual - selector: '.editor.is-focused .cursor' + selector: '.editor .cursor' properties: 'border-color': '#A7A7A7' expect(rulesets[2]).toEqual - selector: '.editor.is-focused .selection .region' + selector: '.editor .selection .region' properties: 'background-color': "rgba(221, 240, 255, 0.2)" diff --git a/spec/app/window-spec.coffee b/spec/app/window-spec.coffee index 5cca06198..6bce6737c 100644 --- a/spec/app/window-spec.coffee +++ b/spec/app/window-spec.coffee @@ -14,12 +14,12 @@ describe "Window", -> $(window).off 'beforeunload' describe "window is loaded", -> - it "has .is-focused on the body tag", -> - expect($("body").hasClass("is-focused")).toBe true + it "doesn't have .is-blurred on the body tag", -> + expect($("body").hasClass("is-blurred")).toBe false - it "doesn't have .is-focused on the window blur event", -> + it "does have .is-blurred on the window blur event", -> $(window).blur() - expect($("body").hasClass("is-focused")).toBe false + expect($("body").hasClass("is-blurred")).toBe true describe ".close()", -> it "is triggered by the 'core:close' event", -> diff --git a/static/editor.css b/static/editor.css index 91aed0439..4c7eac274 100644 --- a/static/editor.css +++ b/static/editor.css @@ -138,8 +138,8 @@ border-left: 1px solid; } -.editor:not(.is-focused) .cursor, -.editor.is-focused .cursor.blink-off { +.is-blurred .cursor, +.editor .cursor.blink-off { visibility: hidden; } diff --git a/themes/atom-dark-syntax.css b/themes/atom-dark-syntax.css index 92f39d650..5f19316c2 100644 --- a/themes/atom-dark-syntax.css +++ b/themes/atom-dark-syntax.css @@ -3,15 +3,15 @@ color: #c5c8c6; } -.editor.is-focused .cursor { +.editor .cursor { border-color: #FFFFFF; } -.editor.is-focused .selection .region { +.editor .selection .region { background-color: #333333; } -.editor.is-focused .line-number.cursor-line-no-selection, .editor.is-focused .line.cursor-line { +.editor .line-number.cursor-line-no-selection, .editor .line.cursor-line { background-color: rgba(255, 255, 255, 0.14); } From 951f6128ca95045800d1d2bd028d0b0254c0d47a Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Mon, 4 Feb 2013 16:06:52 -0800 Subject: [PATCH 03/32] kill some is-focused tab styles --- themes/atom-dark-ui/tabs.css | 51 +++++++----------------------------- 1 file changed, 9 insertions(+), 42 deletions(-) diff --git a/themes/atom-dark-ui/tabs.css b/themes/atom-dark-ui/tabs.css index 7a3d8b394..81b52334e 100644 --- a/themes/atom-dark-ui/tabs.css +++ b/themes/atom-dark-ui/tabs.css @@ -4,7 +4,7 @@ box-shadow: inset 0 -1px 0 #2e2e2e, 0 1px 0 #191919; } -.is-focused .tab { +.tab { background-image: -webkit-linear-gradient(#444, #3d3d3d); border-top: 1px solid #383838; border-right: 1px solid #2e2e2e; @@ -12,38 +12,16 @@ box-shadow: inset 0 0 5px #383838, 0 1px 0 #585858, inset -1px 0 0 #4a4a4a, inset 1px 0 0 #4a4a4a; } -.is-focused .tab:first-child { + .tab:first-child { box-shadow: inset 0 0 5px #383838, 0 1px 0 #585858, inset -1px 0 0 #4a4a4a; } -.is-focused .tab.active, -.is-focused .tab.active:hover { - border-top: 1px solid #4a4a4a; - box-shadow: inset -1px 0 0 #595959, inset 1px 0 0 #595959; - border-bottom-color: #424242; - background-image: -webkit-linear-gradient(#555555, #424242); -} - -.tab { - background-color: #555; - background-image: none; - border-top: 1px solid #383838; - border-right: 1px solid #2e2e2e; - border-bottom: 1px solid #2e2e2e; - box-shadow: inset 0 0 5px #555, 0 1px 0 #585858, inset -1px 0 0 #4a4a4a, inset 1px 0 0 #4a4a4a; -} - -.tab:first-child { - box-shadow: inset 0 0 5px #555, 0 1px 0 #585858, inset -1px 0 0 #4a4a4a; -} - .tab.active, .tab.active:hover { border-top: 1px solid #4a4a4a; box-shadow: inset -1px 0 0 #595959, inset 1px 0 0 #595959; border-bottom-color: #424242; - background-image: none; - background-color: #424242; + background-image: -webkit-linear-gradient(#555555, #424242); } .tab, @@ -55,9 +33,9 @@ border-color: #aaa; } -.is-focused .tab.active, -.is-focused .tab.active:hover, -.is-focused .tab.active .close-icon { +.tab.active, +.tab.active:hover, +.tab.active .close-icon { color: #e6e6e6; } @@ -74,8 +52,8 @@ border: 3px solid #777; } -.is-focused .tab.active:first-child, -.is-focused .tab.active:first-child:hover { +.tab.active:first-child, +.tab.active:first-child:hover { box-shadow: inset -1px 0 0 #595959; } @@ -84,18 +62,6 @@ border: 1px solid #595959; } -.is-focused .tab.active:before { - border-bottom-right-radius: 4px; - border-width: 0 1px 1px 0; - box-shadow: 2px 2px 0 #424242; -} - -.is-focused .tab.active:after { - border-bottom-left-radius: 4px; - border-width: 0 0 1px 1px; - box-shadow: -2px 2px 0 #424242; -} - .tab.active:before { border-bottom-right-radius: 4px; border-width: 0 1px 1px 0; @@ -104,6 +70,7 @@ .tab.active:after { border-bottom-left-radius: 4px; + border-width: 0 0 1px 1px; box-shadow: -2px 2px 0 #424242; } From f8855ef2e36bc19fa0aca95e055ce8e0b7438fc4 Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Mon, 4 Feb 2013 16:20:07 -0800 Subject: [PATCH 04/32] the editor has it's own blurred state independent of the window --- src/app/editor.coffee | 2 ++ static/editor.css | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 7d6dcb054..83ebbbd6c 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -351,10 +351,12 @@ class Editor extends View @hiddenInput.on 'focus', => @rootView()?.editorFocused(this) @isFocused = true + @removeClass 'is-blurred' @hiddenInput.on 'focusout', => @isFocused = false @autosave() if config.get "editor.autosave" + @addClass 'is-blurred' @underlayer.on 'click', (e) => return unless e.target is @underlayer[0] diff --git a/static/editor.css b/static/editor.css index 4c7eac274..86b463bda 100644 --- a/static/editor.css +++ b/static/editor.css @@ -76,6 +76,10 @@ opacity: 1; } +.editor.is-blurred .line.cursor-line { + opacity: 0; +} + .editor .invisible { opacity: 0.2; } @@ -156,3 +160,7 @@ pointer-events: none; z-index: -1; } + +.editor.is-blurred .selection .region { + opacity: 0; +} From aa95590e6c0a18fabc0d0e648a07fa5617450765 Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Mon, 4 Feb 2013 16:20:40 -0800 Subject: [PATCH 05/32] kill is-focused on the dark tree-view --- themes/atom-dark-ui/tree-view.css | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/themes/atom-dark-ui/tree-view.css b/themes/atom-dark-ui/tree-view.css index 2b9383d63..a51e58c44 100644 --- a/themes/atom-dark-ui/tree-view.css +++ b/themes/atom-dark-ui/tree-view.css @@ -1,10 +1,5 @@ -.is-focused .tree-view { - background: #1e1e1e; - border-right: 1px solid #191919; -} - .tree-view { - background: #2e2e2e; + background: #1e1e1e; border-right: 1px solid #191919; } @@ -17,13 +12,8 @@ color: #d2d2d2; } -.is-focused .tree-view .selected > .highlight { - background-image: -webkit-linear-gradient(#4e4e4e, #434343); -} - .tree-view .selected > .highlight { - background-image: none; - background-color: #6e6e6e; + background-image: -webkit-linear-gradient(#4e4e4e, #434343); } .tree-view:focus .selected > .highlight { From 022b5fb88ca025c7be0065c105e199eaa964ac06 Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Mon, 4 Feb 2013 16:42:46 -0800 Subject: [PATCH 06/32] use is-focused for the editor because it needs it's own state independent of the window state --- src/app/editor.coffee | 4 ++-- static/editor.css | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 83ebbbd6c..2e994dc44 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -351,12 +351,12 @@ class Editor extends View @hiddenInput.on 'focus', => @rootView()?.editorFocused(this) @isFocused = true - @removeClass 'is-blurred' + @addClass 'is-focused' @hiddenInput.on 'focusout', => @isFocused = false @autosave() if config.get "editor.autosave" - @addClass 'is-blurred' + @removeClass 'is-focused' @underlayer.on 'click', (e) => return unless e.target is @underlayer[0] diff --git a/static/editor.css b/static/editor.css index 86b463bda..83ee6efb2 100644 --- a/static/editor.css +++ b/static/editor.css @@ -77,7 +77,7 @@ } .editor.is-blurred .line.cursor-line { - opacity: 0; + background: rgba(0, 0, 0, 0); } .editor .invisible { @@ -142,11 +142,15 @@ border-left: 1px solid; } -.is-blurred .cursor, -.editor .cursor.blink-off { +.editor .cursor, +.editor.is-focused .cursor.blink-off { visibility: hidden; } +.editor.is-focused .cursor { + visibility: visible; +} + .editor .hidden-input { position: absolute; z-index: -1; @@ -160,7 +164,3 @@ pointer-events: none; z-index: -1; } - -.editor.is-blurred .selection .region { - opacity: 0; -} From fa0d5b4ab21e6be66a623e031fec28694f63d1e0 Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Mon, 4 Feb 2013 16:50:32 -0800 Subject: [PATCH 07/32] add blurred css --- themes/atom-dark-ui/blurred.css | 11 +++++++++++ themes/atom-dark-ui/package.json | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 themes/atom-dark-ui/blurred.css diff --git a/themes/atom-dark-ui/blurred.css b/themes/atom-dark-ui/blurred.css new file mode 100644 index 000000000..731894849 --- /dev/null +++ b/themes/atom-dark-ui/blurred.css @@ -0,0 +1,11 @@ +.is-blurred .tree-view { + background-color: #222; +} + +.is-blurred .tree-view * { + opacity: 0.9; +} + +.is-blurred .tabs { + opacity: 0.8; +} \ No newline at end of file diff --git a/themes/atom-dark-ui/package.json b/themes/atom-dark-ui/package.json index d0a007f7f..e4c21621f 100644 --- a/themes/atom-dark-ui/package.json +++ b/themes/atom-dark-ui/package.json @@ -8,6 +8,7 @@ "status-bar.css", "markdown-preview.css", "command-panel.css", - "command-logger.css" + "command-logger.css", + "blurred.css" ] } From eb8d6f9766d4e0f0383a5b928f83baf50b1881ab Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Mon, 4 Feb 2013 17:07:27 -0800 Subject: [PATCH 08/32] fix textmate editor specs --- spec/app/text-mate-theme-spec.coffee | 4 ++-- themes/atom-dark-ui/blurred.css | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/app/text-mate-theme-spec.coffee b/spec/app/text-mate-theme-spec.coffee index 4ed7b84e2..b2f6e54fe 100644 --- a/spec/app/text-mate-theme-spec.coffee +++ b/spec/app/text-mate-theme-spec.coffee @@ -27,12 +27,12 @@ describe "TextMateTheme", -> 'color': '#F8F8F8' expect(rulesets[1]).toEqual - selector: '.editor .cursor' + selector: '.editor.is-focused .cursor' properties: 'border-color': '#A7A7A7' expect(rulesets[2]).toEqual - selector: '.editor .selection .region' + selector: '.editor.is-focused .selection .region' properties: 'background-color': "rgba(221, 240, 255, 0.2)" diff --git a/themes/atom-dark-ui/blurred.css b/themes/atom-dark-ui/blurred.css index 731894849..72aaf7dd8 100644 --- a/themes/atom-dark-ui/blurred.css +++ b/themes/atom-dark-ui/blurred.css @@ -3,7 +3,7 @@ } .is-blurred .tree-view * { - opacity: 0.9; + opacity: 0.95; } .is-blurred .tabs { From 0270ba3e1c7900e5fc0a620f09ccce655a7d27d6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 4 Feb 2013 15:23:14 -0800 Subject: [PATCH 09/32] Add bracket matcher that highlights pair (), {}, and [] pairs are now highlighted when after or before the cursor --- src/app/edit-session.coffee | 3 + src/app/editor.coffee | 1 + src/packages/bracket-matcher/index.coffee | 94 +++++++++++++++++++ .../spec/bracket-matcher-spec.coffee | 60 ++++++++++++ .../stylesheets/bracket-matcher.css | 3 + themes/atom-dark-ui/bracket-matcher.css | 5 + themes/atom-dark-ui/package.json | 3 +- themes/atom-light-ui/bracket-matcher.css | 5 + themes/atom-light-ui/package.json | 3 +- 9 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 src/packages/bracket-matcher/index.coffee create mode 100644 src/packages/bracket-matcher/spec/bracket-matcher-spec.coffee create mode 100644 src/packages/bracket-matcher/stylesheets/bracket-matcher.css create mode 100644 themes/atom-dark-ui/bracket-matcher.css create mode 100644 themes/atom-light-ui/bracket-matcher.css diff --git a/src/app/edit-session.coffee b/src/app/edit-session.coffee index f6248c173..838a13b76 100644 --- a/src/app/edit-session.coffee +++ b/src/app/edit-session.coffee @@ -307,6 +307,9 @@ class EditSession fold.destroy() @setCursorBufferPosition([fold.startRow, 0]) + isFoldedAtCursorRow: -> + @isFoldedAtScreenRow(@getCursorScreenRow()) + isFoldedAtBufferRow: (bufferRow) -> screenRow = @screenPositionForBufferPosition([bufferRow]).row @isFoldedAtScreenRow(screenRow) diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 161e7505e..738f8269c 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -277,6 +277,7 @@ class Editor extends View destroyFoldsContainingBufferRow: (bufferRow) -> @activeEditSession.destroyFoldsContainingBufferRow(bufferRow) isFoldedAtScreenRow: (screenRow) -> @activeEditSession.isFoldedAtScreenRow(screenRow) isFoldedAtBufferRow: (bufferRow) -> @activeEditSession.isFoldedAtBufferRow(bufferRow) + isFoldedAtCursorRow: -> @activeEditSession.isFoldedAtCursorRow() lineForScreenRow: (screenRow) -> @activeEditSession.lineForScreenRow(screenRow) linesForScreenRows: (start, end) -> @activeEditSession.linesForScreenRows(start, end) diff --git a/src/packages/bracket-matcher/index.coffee b/src/packages/bracket-matcher/index.coffee new file mode 100644 index 000000000..aeb18f60c --- /dev/null +++ b/src/packages/bracket-matcher/index.coffee @@ -0,0 +1,94 @@ +AtomPackage = require 'atom-package' +_ = require 'underscore' +{$$} = require 'space-pen' +Range = require 'range' + +module.exports = +class BracketMatcher extends AtomPackage + startPairMatches: + '(': ')' + '[': ']' + '{': '}' + + endPairMatches: + ')': '(' + ']': '[' + '}': '{' + + pairHighlighted: false + + activate: (rootView) -> + rootView.eachEditor (editor) => @subscribeToEditor(editor) if editor.attached + + subscribeToEditor: (editor) -> + editor.on 'cursor:moved', => @updateMatch(editor) + + createView: (editor, bufferPosition) -> + pixelPosition = editor.pixelPositionForBufferPosition(bufferPosition) + view = $$ -> @div class: 'bracket-matcher' + view.css('top', pixelPosition.top).css('left', pixelPosition.left) + view.width(editor.charWidth).height(editor.charHeight) + + findCurrentPair: (editor, buffer, matches) -> + position = editor.getCursorBufferPosition() + currentPair = buffer.getTextInRange(Range.fromPointWithDelta(position, 0, 1)) + unless matches[currentPair] + position = position.translate([0, -1]) + currentPair = buffer.getTextInRange(Range.fromPointWithDelta(position, 0, 1)) + matchingPair = matches[currentPair] + if matchingPair + {position, currentPair, matchingPair} + else + {} + + findMatchingEndPair: (buffer, startPairPosition, startPair, endPair) -> + scanRange = new Range(startPairPosition.translate([0, 1]), buffer.getEofPosition()) + regex = new RegExp("[#{_.escapeRegExp(startPair + endPair)}]", 'g') + endPairPosition = null + unpairedCount = 0 + buffer.scanInRange regex, scanRange, (match, range, {stop}) => + if match[0] is startPair + unpairedCount++ + else if match[0] is endPair + unpairedCount-- + endPairPosition = range.start + stop() if unpairedCount < 0 + endPairPosition + + findMatchingStartPair: (buffer, endPairPosition, startPair, endPair) -> + scanRange = new Range([0, 0], endPairPosition) + regex = new RegExp("[#{_.escapeRegExp(startPair + endPair)}]", 'g') + startPairPosition = null + unpairedCount = 0 + scanner = (match, range, {stop}) => + if match[0] is endPair + unpairedCount++ + else if match[0] is startPair + unpairedCount-- + startPairPosition = range.start + stop() if unpairedCount < 0 + buffer.scanInRange(regex, scanRange, scanner, true) + startPairPosition + + updateMatch: (editor) -> + return unless underlayer = editor.pane()?.find('.underlayer') + + underlayer.find('.bracket-matcher').remove() if @pairHighlighted + @pairHighlighted = false + + return unless editor.getSelection().isEmpty() + return if editor.isFoldedAtCursorRow() + + buffer = editor.getBuffer() + {position, currentPair, matchingPair} = @findCurrentPair(editor, buffer, @startPairMatches) + if position + matchPosition = @findMatchingEndPair(buffer, position, currentPair, matchingPair) + else + {position, currentPair, matchingPair} = @findCurrentPair(editor, buffer, @endPairMatches) + if position + matchPosition = @findMatchingStartPair(buffer, position, matchingPair, currentPair) + + if position? and matchPosition? + underlayer.append(@createView(editor, position)) + underlayer.append(@createView(editor, matchPosition)) + @pairHighlighted = true diff --git a/src/packages/bracket-matcher/spec/bracket-matcher-spec.coffee b/src/packages/bracket-matcher/spec/bracket-matcher-spec.coffee new file mode 100644 index 000000000..8b1e1708d --- /dev/null +++ b/src/packages/bracket-matcher/spec/bracket-matcher-spec.coffee @@ -0,0 +1,60 @@ +RootView = require 'root-view' + +describe "bracket matching", -> + [rootView, editor] = [] + + beforeEach -> + rootView = new RootView(require.resolve('fixtures/sample.js')) + atom.loadPackage('bracket-matcher') + rootView.attachToDom() + editor = rootView.getActiveEditor() + + afterEach -> + rootView.deactivate() + + describe "when the cursor is before a starting pair", -> + it "highlights the starting pair and ending pair", -> + editor.moveCursorToEndOfLine() + editor.moveCursorLeft() + expect(editor.underlayer.find('.bracket-matcher').length).toBe 2 + expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28]) + expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0]) + + describe "when the cursor is after a starting pair", -> + it "highlights the starting pair and ending pair", -> + editor.moveCursorToEndOfLine() + expect(editor.underlayer.find('.bracket-matcher').length).toBe 2 + expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28]) + expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0]) + + describe "when the cursor is before an ending pair", -> + it "highlights the starting pair and ending pair", -> + editor.moveCursorToBottom() + editor.moveCursorLeft() + editor.moveCursorLeft() + expect(editor.underlayer.find('.bracket-matcher').length).toBe 2 + expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([12,0]) + expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,28]) + + describe "when the cursor is after an ending pair", -> + it "highlights the starting pair and ending pair", -> + editor.moveCursorToBottom() + editor.moveCursorLeft() + expect(editor.underlayer.find('.bracket-matcher').length).toBe 2 + expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([12,0]) + expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,28]) + + describe "when the cursor is moved off a pair", -> + it "removes the starting pair and ending pair highlights", -> + editor.moveCursorToEndOfLine() + expect(editor.underlayer.find('.bracket-matcher').length).toBe 2 + editor.moveCursorToBeginningOfLine() + expect(editor.underlayer.find('.bracket-matcher').length).toBe 0 + + describe "pair balancing", -> + describe "when a second starting pair preceeds the first ending pair", -> + it "advances to the second ending pair", -> + editor.setCursorBufferPosition([8,42]) + expect(editor.underlayer.find('.bracket-matcher').length).toBe 2 + expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([8,42]) + expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([8,54]) diff --git a/src/packages/bracket-matcher/stylesheets/bracket-matcher.css b/src/packages/bracket-matcher/stylesheets/bracket-matcher.css new file mode 100644 index 000000000..8d77b10de --- /dev/null +++ b/src/packages/bracket-matcher/stylesheets/bracket-matcher.css @@ -0,0 +1,3 @@ +.bracket-matcher { + position: absolute; +} diff --git a/themes/atom-dark-ui/bracket-matcher.css b/themes/atom-dark-ui/bracket-matcher.css new file mode 100644 index 000000000..d579fdc35 --- /dev/null +++ b/themes/atom-dark-ui/bracket-matcher.css @@ -0,0 +1,5 @@ +.bracket-matcher { + border-bottom: 1px solid #f8de7e; + margin-top: -1px; + opacity: .7; +} diff --git a/themes/atom-dark-ui/package.json b/themes/atom-dark-ui/package.json index d0a007f7f..44dd4534d 100644 --- a/themes/atom-dark-ui/package.json +++ b/themes/atom-dark-ui/package.json @@ -8,6 +8,7 @@ "status-bar.css", "markdown-preview.css", "command-panel.css", - "command-logger.css" + "command-logger.css", + "bracket-matcher.css" ] } diff --git a/themes/atom-light-ui/bracket-matcher.css b/themes/atom-light-ui/bracket-matcher.css new file mode 100644 index 000000000..d579fdc35 --- /dev/null +++ b/themes/atom-light-ui/bracket-matcher.css @@ -0,0 +1,5 @@ +.bracket-matcher { + border-bottom: 1px solid #f8de7e; + margin-top: -1px; + opacity: .7; +} diff --git a/themes/atom-light-ui/package.json b/themes/atom-light-ui/package.json index d0a007f7f..44dd4534d 100644 --- a/themes/atom-light-ui/package.json +++ b/themes/atom-light-ui/package.json @@ -8,6 +8,7 @@ "status-bar.css", "markdown-preview.css", "command-panel.css", - "command-logger.css" + "command-logger.css", + "bracket-matcher.css" ] } From b30fae7a682f4ba228b6d6381322c8c5e5e43366 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 4 Feb 2013 18:24:54 -0800 Subject: [PATCH 10/32] Remove event handlers when editor is removed --- src/packages/bracket-matcher/index.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/packages/bracket-matcher/index.coffee b/src/packages/bracket-matcher/index.coffee index aeb18f60c..95a3ff8a8 100644 --- a/src/packages/bracket-matcher/index.coffee +++ b/src/packages/bracket-matcher/index.coffee @@ -21,7 +21,8 @@ class BracketMatcher extends AtomPackage rootView.eachEditor (editor) => @subscribeToEditor(editor) if editor.attached subscribeToEditor: (editor) -> - editor.on 'cursor:moved', => @updateMatch(editor) + editor.on 'cursor:moved.bracket-matcher', => @updateMatch(editor) + editor.on 'editor:will-be-removed', => editor.off('.bracket-matcher') createView: (editor, bufferPosition) -> pixelPosition = editor.pixelPositionForBufferPosition(bufferPosition) From 39e39afa1b15c5bcde718b14ba403944dc9fc743 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 4 Feb 2013 20:38:15 -0800 Subject: [PATCH 11/32] Bind ctrl-j to jump to matching bracket --- src/packages/bracket-matcher/index.coffee | 28 +++++++++++++-- .../keymaps/bracket-matcher.cson | 2 ++ .../spec/bracket-matcher-spec.coffee | 34 ++++++++++++++++--- 3 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 src/packages/bracket-matcher/keymaps/bracket-matcher.cson diff --git a/src/packages/bracket-matcher/index.coffee b/src/packages/bracket-matcher/index.coffee index 95a3ff8a8..783868c5d 100644 --- a/src/packages/bracket-matcher/index.coffee +++ b/src/packages/bracket-matcher/index.coffee @@ -22,11 +22,31 @@ class BracketMatcher extends AtomPackage subscribeToEditor: (editor) -> editor.on 'cursor:moved.bracket-matcher', => @updateMatch(editor) + editor.command 'editor:go-to-matching-bracket', => @goToMatchingPair(editor) editor.on 'editor:will-be-removed', => editor.off('.bracket-matcher') + goToMatchingPair: (editor) -> + return unless @pairHighlighted + return unless underlayer = editor.pane()?.find('.underlayer') + + position = editor.getCursorBufferPosition() + previousPosition = position.translate([0, -1]) + startPosition = underlayer.find('.bracket-matcher:first').data('bufferPosition') + endPosition = underlayer.find('.bracket-matcher:last').data('bufferPosition') + + if position.isEqual(startPosition) + editor.setCursorBufferPosition(endPosition.translate([0, 1])) + else if previousPosition.isEqual(startPosition) + editor.setCursorBufferPosition(endPosition) + else if position.isEqual(endPosition) + editor.setCursorBufferPosition(startPosition.translate([0, 1])) + else if previousPosition.isEqual(endPosition) + editor.setCursorBufferPosition(startPosition) + createView: (editor, bufferPosition) -> pixelPosition = editor.pixelPositionForBufferPosition(bufferPosition) view = $$ -> @div class: 'bracket-matcher' + view.data('bufferPosition', bufferPosition) view.css('top', pixelPosition.top).css('left', pixelPosition.left) view.width(editor.charWidth).height(editor.charHeight) @@ -90,6 +110,10 @@ class BracketMatcher extends AtomPackage matchPosition = @findMatchingStartPair(buffer, position, matchingPair, currentPair) if position? and matchPosition? - underlayer.append(@createView(editor, position)) - underlayer.append(@createView(editor, matchPosition)) + if position.isLessThan(matchPosition) + underlayer.append(@createView(editor, position)) + underlayer.append(@createView(editor, matchPosition)) + else + underlayer.append(@createView(editor, matchPosition)) + underlayer.append(@createView(editor, position)) @pairHighlighted = true diff --git a/src/packages/bracket-matcher/keymaps/bracket-matcher.cson b/src/packages/bracket-matcher/keymaps/bracket-matcher.cson new file mode 100644 index 000000000..672df9be6 --- /dev/null +++ b/src/packages/bracket-matcher/keymaps/bracket-matcher.cson @@ -0,0 +1,2 @@ +'.editor': + 'ctrl-j': 'editor:go-to-matching-bracket' diff --git a/src/packages/bracket-matcher/spec/bracket-matcher-spec.coffee b/src/packages/bracket-matcher/spec/bracket-matcher-spec.coffee index 8b1e1708d..69e882502 100644 --- a/src/packages/bracket-matcher/spec/bracket-matcher-spec.coffee +++ b/src/packages/bracket-matcher/spec/bracket-matcher-spec.coffee @@ -33,16 +33,16 @@ describe "bracket matching", -> editor.moveCursorLeft() editor.moveCursorLeft() expect(editor.underlayer.find('.bracket-matcher').length).toBe 2 - expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([12,0]) - expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,28]) + expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0]) + expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28]) describe "when the cursor is after an ending pair", -> it "highlights the starting pair and ending pair", -> editor.moveCursorToBottom() editor.moveCursorLeft() expect(editor.underlayer.find('.bracket-matcher').length).toBe 2 - expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([12,0]) - expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,28]) + expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0]) + expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28]) describe "when the cursor is moved off a pair", -> it "removes the starting pair and ending pair highlights", -> @@ -58,3 +58,29 @@ describe "bracket matching", -> expect(editor.underlayer.find('.bracket-matcher').length).toBe 2 expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([8,42]) expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([8,54]) + + describe "when editor:go-to-matching-bracket is triggered", -> + describe "when the cursor is before the starting pair", -> + it "moves the cursor to after the ending pair", -> + editor.moveCursorToEndOfLine() + editor.moveCursorLeft() + editor.trigger "editor:go-to-matching-bracket" + expect(editor.getCursorBufferPosition()).toEqual [12, 1] + + describe "when the cursor is after the starting pair", -> + it "moves the cursor to before the ending pair", -> + editor.moveCursorToEndOfLine() + editor.trigger "editor:go-to-matching-bracket" + expect(editor.getCursorBufferPosition()).toEqual [12, 0] + + describe "when the cursor is before the ending pair", -> + it "moves the cursor to after the starting pair", -> + editor.setCursorBufferPosition([12, 0]) + editor.trigger "editor:go-to-matching-bracket" + expect(editor.getCursorBufferPosition()).toEqual [0, 29] + + describe "when the cursor is after the ending pair", -> + it "moves the cursor to before the starting pair", -> + editor.setCursorBufferPosition([12, 1]) + editor.trigger "editor:go-to-matching-bracket" + expect(editor.getCursorBufferPosition()).toEqual [0, 28] From b0b38079e0f169fb730d73339c6e771434511814 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 4 Feb 2013 20:50:14 -0800 Subject: [PATCH 12/32] Migrate template config file to cson --- .atom/config.cson | 7 +++++++ .atom/config.json | 11 ----------- 2 files changed, 7 insertions(+), 11 deletions(-) create mode 100644 .atom/config.cson delete mode 100644 .atom/config.json diff --git a/.atom/config.cson b/.atom/config.cson new file mode 100644 index 000000000..a93b83e66 --- /dev/null +++ b/.atom/config.cson @@ -0,0 +1,7 @@ +'editor': + 'fontSize': 16 +'core': + 'themes': [ + 'atom-dark-ui' + 'atom-dark-syntax' + ] diff --git a/.atom/config.json b/.atom/config.json deleted file mode 100644 index 50770e810..000000000 --- a/.atom/config.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "editor": { - "fontSize": 16 - }, - "core": { - "themes": [ - "atom-dark-ui", - "atom-dark-syntax" - ] - } -} From 651d305f761ace9e40b38f14b84f04c339d87acd Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 4 Feb 2013 20:56:25 -0800 Subject: [PATCH 13/32] Add package namespace to command registration --- src/packages/bracket-matcher/index.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/packages/bracket-matcher/index.coffee b/src/packages/bracket-matcher/index.coffee index 783868c5d..081ca9923 100644 --- a/src/packages/bracket-matcher/index.coffee +++ b/src/packages/bracket-matcher/index.coffee @@ -22,7 +22,8 @@ class BracketMatcher extends AtomPackage subscribeToEditor: (editor) -> editor.on 'cursor:moved.bracket-matcher', => @updateMatch(editor) - editor.command 'editor:go-to-matching-bracket', => @goToMatchingPair(editor) + editor.command 'editor:go-to-matching-bracket.bracket-matcher', => + @goToMatchingPair(editor) editor.on 'editor:will-be-removed', => editor.off('.bracket-matcher') goToMatchingPair: (editor) -> From 3514048893579f7ec49f599d344418f5d550a379 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 4 Feb 2013 21:20:17 -0800 Subject: [PATCH 14/32] Exclude background window from expose Previously you would see an untitled empty space when showing application windows with ctrl-down. --- native/atom_window_controller.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/native/atom_window_controller.mm b/native/atom_window_controller.mm index d61e46063..4a26e9601 100644 --- a/native/atom_window_controller.mm +++ b/native/atom_window_controller.mm @@ -69,6 +69,7 @@ [self initWithBootstrapScript:@"window-bootstrap" background:YES alwaysUseBundleResourcePath:stable]; [self.window setFrame:NSMakeRect(0, 0, 0, 0) display:NO]; [self.window setExcludedFromWindowsMenu:YES]; + [self.window setCollectionBehavior:NSWindowCollectionBehaviorStationary]; return self; } From 55d282fdd40e428af895ee2283e73dc138d687aa Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Tue, 5 Feb 2013 08:22:14 -0800 Subject: [PATCH 15/32] valid json --- themes/atom-dark-ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/atom-dark-ui/package.json b/themes/atom-dark-ui/package.json index 177ed813e..b223f8deb 100644 --- a/themes/atom-dark-ui/package.json +++ b/themes/atom-dark-ui/package.json @@ -9,7 +9,7 @@ "markdown-preview.css", "command-panel.css", "command-logger.css", - "blurred.css" + "blurred.css", "bracket-matcher.css" ] } From 0bd6ce7ae110f6fc12e5870174c4d247d6796f22 Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Tue, 5 Feb 2013 08:38:08 -0800 Subject: [PATCH 16/32] more subtle look for blurred state in atom-dark-ui --- themes/atom-dark-ui/blurred.css | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/themes/atom-dark-ui/blurred.css b/themes/atom-dark-ui/blurred.css index 72aaf7dd8..cb9601b51 100644 --- a/themes/atom-dark-ui/blurred.css +++ b/themes/atom-dark-ui/blurred.css @@ -1,11 +1,21 @@ .is-blurred .tree-view { - background-color: #222; -} - -.is-blurred .tree-view * { - opacity: 0.95; + background-color: #2a2a2a; } .is-blurred .tabs { opacity: 0.8; + border-bottom-color: #525252; +} + +.is-blurred .tab { + background-image: -webkit-linear-gradient(#444, #555); +} + +.is-blurred .tab.active { + border: 1px solid #525252 +} + +.is-blurred .tab.active:before { + box-shadow: 2px 2px 0 #525252; + border-color: #696969; } \ No newline at end of file From 7a88e4bdb6f841edd2c16df50523dd0b629f5fe8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 5 Feb 2013 08:41:54 -0800 Subject: [PATCH 17/32] Add markdown link color --- themes/atom-dark-ui/markdown-preview.css | 4 ++++ themes/atom-light-ui/markdown-preview.css | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/themes/atom-dark-ui/markdown-preview.css b/themes/atom-dark-ui/markdown-preview.css index f5274f2df..5d58e2de7 100644 --- a/themes/atom-dark-ui/markdown-preview.css +++ b/themes/atom-dark-ui/markdown-preview.css @@ -29,6 +29,10 @@ font-family: Consolas, "Liberation Mono", Courier, monospace; } +.markdown-body a { + color: #4183c4; +} + .markdown-body ol > li { list-style-type: decimal; } diff --git a/themes/atom-light-ui/markdown-preview.css b/themes/atom-light-ui/markdown-preview.css index f5274f2df..5d58e2de7 100644 --- a/themes/atom-light-ui/markdown-preview.css +++ b/themes/atom-light-ui/markdown-preview.css @@ -29,6 +29,10 @@ font-family: Consolas, "Liberation Mono", Courier, monospace; } +.markdown-body a { + color: #4183c4; +} + .markdown-body ol > li { list-style-type: decimal; } From 5af967ac4b9e72a815711290fe83933766b1f32a Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Tue, 5 Feb 2013 08:46:54 -0800 Subject: [PATCH 18/32] update blurred styles for atom-light-ui --- themes/atom-light-ui/blurred.css | 25 ++++++++++++++++++++++++ themes/atom-light-ui/package.json | 1 + themes/atom-light-ui/tabs.css | 12 +----------- themes/atom-light-ui/tree-view.css | 31 ++++-------------------------- 4 files changed, 31 insertions(+), 38 deletions(-) create mode 100644 themes/atom-light-ui/blurred.css diff --git a/themes/atom-light-ui/blurred.css b/themes/atom-light-ui/blurred.css new file mode 100644 index 000000000..8674f81ba --- /dev/null +++ b/themes/atom-light-ui/blurred.css @@ -0,0 +1,25 @@ +.is-blurred .tab { + background-image: none; + background-color: #e0e0e0); + border-top: none; + border-right: 1px solid #959595; + border-bottom: 1px solid #959595; + box-shadow: inset 0 0 5px #eee, 0 1px 0 #eee, inset -1px 0 0 #e0e0e0, inset 1px 0 0 #e0e0e0; + color: #323232; +} + +.is-blurred .tree-view { + background: #f3f3f3; + border-right: 1px solid #c5c5c5; +} + +.is-blurred .tree-view:focus .selected > .highlight { + border-top: 1px solid #3D4552; + border-bottom: 1px solid #3D4552; + background-image: none; + background-color: #69717b; +} + +.is-blurred .tree-view .name:before { + color: #7e7e7e; +} diff --git a/themes/atom-light-ui/package.json b/themes/atom-light-ui/package.json index 44dd4534d..b223f8deb 100644 --- a/themes/atom-light-ui/package.json +++ b/themes/atom-light-ui/package.json @@ -9,6 +9,7 @@ "markdown-preview.css", "command-panel.css", "command-logger.css", + "blurred.css", "bracket-matcher.css" ] } diff --git a/themes/atom-light-ui/tabs.css b/themes/atom-light-ui/tabs.css index 7bdba5938..6c37140a7 100644 --- a/themes/atom-light-ui/tabs.css +++ b/themes/atom-light-ui/tabs.css @@ -4,18 +4,8 @@ box-shadow: inset 0 -1px 0 #959595, 0 1px 0 #989898; } -.is-focused .tab { - background-image: -webkit-linear-gradient(#e0e0e0, #bfbfbf); - border-top: none; - border-right: 1px solid #959595; - border-bottom: 1px solid #959595; - box-shadow: inset 0 0 5px #eee, 0 1px 0 #eee, inset -1px 0 0 #e0e0e0, inset 1px 0 0 #e0e0e0; - color: #323232; -} - .tab { - background-image: none; - background-color: #e0e0e0); + background-image: -webkit-linear-gradient(#e0e0e0, #bfbfbf); border-top: none; border-right: 1px solid #959595; border-bottom: 1px solid #959595; diff --git a/themes/atom-light-ui/tree-view.css b/themes/atom-light-ui/tree-view.css index 638c58669..ff18a5990 100644 --- a/themes/atom-light-ui/tree-view.css +++ b/themes/atom-light-ui/tree-view.css @@ -1,13 +1,8 @@ -.is-focused .tree-view { +.tree-view { background: #dde3e8; border-right: 1px solid #989898; } -.tree-view { - background: #f3f3f3; - border-right: 1px solid #c5c5c5; -} - .tree-view .entry { text-shadow: 0 1px 0 #fff; } @@ -17,7 +12,7 @@ color: #262626; } -.is-focused .tree-view .selected > .highlight { +.tree-view .selected > .highlight { box-sizing: border-box; border-top: 1px solid #97a4a7; border-bottom: 1px solid #97a4a7; @@ -25,25 +20,10 @@ background-image: -webkit-linear-gradient(#cad5d8, #bcccce); } -.tree-view .selected > .highlight { - box-sizing: border-box; - border-top: 1px solid #97a4a7; - border-bottom: 1px solid #97a4a7; - background-image: none; - background-color: #DFDFDF; -} - -.is-focused .tree-view:focus .selected > .highlight { - border-top: 1px solid #3D4552; - border-bottom: 1px solid #3D4552; - background-image: -webkit-linear-gradient(#7e868d, #69717b); -} - .tree-view:focus .selected > .highlight { border-top: 1px solid #3D4552; border-bottom: 1px solid #3D4552; - background-image: none; - background-color: #69717b; + background-image: -webkit-linear-gradient(#7e868d, #69717b); } .tree-view:focus .directory.selected > .header > .name, @@ -62,13 +42,10 @@ color: #262626; } -.is-focused .tree-view .name:before { +.tree-view .name:before { color: #7e8692; } -.tree-view .name:before { - color: #7e7e7e; -} .tree-view .entry:hover, .tree-view .directory .header:hover .name, From 8347b14ab312272f2bbf73b984dd3a6eb4bec49a Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Tue, 5 Feb 2013 08:59:21 -0800 Subject: [PATCH 19/32] the tabs needed some is-blurred action for the active tab --- themes/atom-light-ui/blurred.css | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/themes/atom-light-ui/blurred.css b/themes/atom-light-ui/blurred.css index 8674f81ba..ad77b0a56 100644 --- a/themes/atom-light-ui/blurred.css +++ b/themes/atom-light-ui/blurred.css @@ -8,6 +8,11 @@ color: #323232; } +.is-blurred .tab.active { + border-bottom: 1px solid #e5e5e5; + box-shadow: inset 0 0 5px #eee, inset -1px 0 0 #e0e0e0, inset 1px 0 0 #e0e0e0; +} + .is-blurred .tree-view { background: #f3f3f3; border-right: 1px solid #c5c5c5; @@ -20,6 +25,13 @@ background-color: #69717b; } +.is-blurred .tree-view:focus .selected > .highlight { + border-top: 1px solid #3D4552; + border-bottom: 1px solid #3D4552; + background-image: none; + background-color: #69717b; +} + .is-blurred .tree-view .name:before { color: #7e7e7e; } From 03055441a9902c7e3537925021d42e8ad042491e Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Tue, 5 Feb 2013 09:01:29 -0800 Subject: [PATCH 20/32] treeview blurred was missing some desaturation --- themes/atom-light-ui/blurred.css | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/themes/atom-light-ui/blurred.css b/themes/atom-light-ui/blurred.css index ad77b0a56..cc085ff29 100644 --- a/themes/atom-light-ui/blurred.css +++ b/themes/atom-light-ui/blurred.css @@ -25,11 +25,12 @@ background-color: #69717b; } -.is-blurred .tree-view:focus .selected > .highlight { - border-top: 1px solid #3D4552; - border-bottom: 1px solid #3D4552; +.is-blurred .tree-view .selected > .highlight { + box-sizing: border-box; + border-top: 1px solid #97a4a7; + border-bottom: 1px solid #97a4a7; background-image: none; - background-color: #69717b; + background-color: #DFDFDF; } .is-blurred .tree-view .name:before { From dbebb919082f2a04edcb00ad6262417415096496 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 5 Feb 2013 09:08:41 -0800 Subject: [PATCH 21/32] Add back README to template packages directory --- .atom/packages/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 .atom/packages/README.md diff --git a/.atom/packages/README.md b/.atom/packages/README.md new file mode 100644 index 000000000..540b6949c --- /dev/null +++ b/.atom/packages/README.md @@ -0,0 +1 @@ +All packages in this directory will be automatically loaded From 9011d623514a0bf4376244ac1d3242756f5e7e50 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 5 Feb 2013 09:15:59 -0800 Subject: [PATCH 22/32] Use octicon for README files --- src/packages/command-panel/src/preview-list.coffee | 5 ++++- src/packages/fuzzy-finder/src/fuzzy-finder-view.coffee | 4 +++- src/packages/tree-view/src/file-view.coffee | 4 +++- src/stdlib/fs.coffee | 6 ++++++ static/command-panel.css | 4 ++++ static/fuzzy-finder.css | 6 +++++- static/tree-view.css | 5 +++++ 7 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/packages/command-panel/src/preview-list.coffee b/src/packages/command-panel/src/preview-list.coffee index cb0296d46..364a6c5b6 100644 --- a/src/packages/command-panel/src/preview-list.coffee +++ b/src/packages/command-panel/src/preview-list.coffee @@ -2,6 +2,7 @@ $ = require 'jquery' {$$$} = require 'space-pen' ScrollView = require 'scroll-view' _ = require 'underscore' +fs = require 'fs' module.exports = class PreviewList extends ScrollView @@ -34,7 +35,9 @@ class PreviewList extends ScrollView operation.index = index for operation, index in operations operationsByPath = _.groupBy(operations, (operation) -> operation.getPath()) for path, ops of operationsByPath - @li class: 'path', => + classes = ['path'] + classes.push('readme') if fs.isReadme(path) + @li class: classes.join(' '), => @span path @span "(#{ops.length})", class: 'path-match-number' for operation in ops diff --git a/src/packages/fuzzy-finder/src/fuzzy-finder-view.coffee b/src/packages/fuzzy-finder/src/fuzzy-finder-view.coffee index 85c2c57d1..17165a8c1 100644 --- a/src/packages/fuzzy-finder/src/fuzzy-finder-view.coffee +++ b/src/packages/fuzzy-finder/src/fuzzy-finder-view.coffee @@ -39,7 +39,9 @@ class FuzzyFinderView extends SelectList $$ -> @li => ext = fs.extension(path) - if fs.isCompressedExtension(ext) + if fs.isReadme(path) + typeClass = 'readme-name' + else if fs.isCompressedExtension(ext) typeClass = 'compressed-name' else if fs.isImageExtension(ext) typeClass = 'image-name' diff --git a/src/packages/tree-view/src/file-view.coffee b/src/packages/tree-view/src/file-view.coffee index ea75356da..142bc5eea 100644 --- a/src/packages/tree-view/src/file-view.coffee +++ b/src/packages/tree-view/src/file-view.coffee @@ -17,7 +17,9 @@ class FileView extends View @subscribe $(window), 'focus', => @updateStatus() extension = fs.extension(@getPath()) - if fs.isCompressedExtension(extension) + if fs.isReadme(@getPath()) + @fileName.addClass('readme-icon') + else if fs.isCompressedExtension(extension) @fileName.addClass('compressed-icon') else if fs.isImageExtension(extension) @fileName.addClass('image-icon') diff --git a/src/stdlib/fs.coffee b/src/stdlib/fs.coffee index 9225913ec..35e9c5510 100644 --- a/src/stdlib/fs.coffee +++ b/src/stdlib/fs.coffee @@ -180,6 +180,12 @@ module.exports = '.ron' ], ext, true) >= 0 + + isReadme: (path) -> + extension = @extension(path) + base = @base(path, extension).toLowerCase() + base is 'readme' and (extension is '' or @isMarkdownExtension(extension)) + readObject: (path) -> contents = @read(path) if @extension(path) is '.cson' diff --git a/static/command-panel.css b/static/command-panel.css index aa6796897..5f10228c4 100644 --- a/static/command-panel.css +++ b/static/command-panel.css @@ -32,6 +32,10 @@ top: 1px; } +.command-panel .preview-list .path.readme:before { + content: "\f007"; +} + .command-panel .preview-list .operation { padding-top: 2px; padding-bottom: 2px; diff --git a/static/fuzzy-finder.css b/static/fuzzy-finder.css index 76ef05462..f480ab0d3 100644 --- a/static/fuzzy-finder.css +++ b/static/fuzzy-finder.css @@ -30,4 +30,8 @@ .fuzzy-finder .file.pdf-name:before { content: "\f014"; -} \ No newline at end of file +} + +.fuzzy-finder .file.readme-name:before { + content: "\f007"; +} diff --git a/static/tree-view.css b/static/tree-view.css index 1568bfbc1..2bf94d527 100644 --- a/static/tree-view.css +++ b/static/tree-view.css @@ -112,6 +112,11 @@ top: -2px; } +.tree-view .file .readme-icon:before { + content: "\f007"; + top: -2px; +} + .tree-view .directory > .header .disclosure-arrow:before { content: "\f05a"; } From 1b2c7faed94bd22e02fa1f04ba390f5d57f43c26 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 5 Feb 2013 09:35:39 -0800 Subject: [PATCH 23/32] Bind ctrl-meta-f to toggle full screen Refs #134 --- native/atom_cef_client.cpp | 3 +++ native/atom_cef_client.h | 1 + native/atom_cef_client_mac.mm | 4 ++++ src/app/atom.coffee | 3 +++ src/app/keymaps/atom.cson | 1 + src/app/window.coffee | 1 + 6 files changed, 13 insertions(+) diff --git a/native/atom_cef_client.cpp b/native/atom_cef_client.cpp index 3acb53951..27badf291 100644 --- a/native/atom_cef_client.cpp +++ b/native/atom_cef_client.cpp @@ -80,6 +80,9 @@ bool AtomCefClient::OnProcessMessageReceived(CefRefPtr browser, else if (name == "show") { Show(browser); } + else if (name == "toggleFullScreen") { + ToggleFullScreen(browser); + } else { return false; } diff --git a/native/atom_cef_client.h b/native/atom_cef_client.h index d1961d8d3..85d9a031b 100644 --- a/native/atom_cef_client.h +++ b/native/atom_cef_client.h @@ -124,6 +124,7 @@ class AtomCefClient : public CefClient, void Exit(int status); void Log(const char *message); void Show(CefRefPtr browser); + void ToggleFullScreen(CefRefPtr browser); IMPLEMENT_REFCOUNTING(AtomCefClient); IMPLEMENT_LOCKING(AtomCefClient); diff --git a/native/atom_cef_client_mac.mm b/native/atom_cef_client_mac.mm index be4879d97..d2f250ec0 100644 --- a/native/atom_cef_client_mac.mm +++ b/native/atom_cef_client_mac.mm @@ -118,6 +118,10 @@ void AtomCefClient::Show(CefRefPtr browser) { [windowController.webView setHidden:NO]; } +void AtomCefClient::ToggleFullScreen(CefRefPtr browser) { + [[browser->GetHost()->GetWindowHandle() window] toggleFullScreen:nil]; +} + void AtomCefClient::ShowSaveDialog(int replyId, CefRefPtr browser) { CefRefPtr replyMessage = CefProcessMessage::Create("reply"); CefRefPtr replyArguments = replyMessage->GetArgumentList(); diff --git a/src/app/atom.coffee b/src/app/atom.coffee index e5eb0197f..b080e03bb 100644 --- a/src/app/atom.coffee +++ b/src/app/atom.coffee @@ -111,6 +111,9 @@ _.extend atom, endTracing: -> @sendMessageToBrowserProcess('endTracing') + toggleFullScreen: -> + @sendMessageToBrowserProcess('toggleFullScreen') + getRootViewStateForPath: (path) -> if json = localStorage[path] JSON.parse(json) diff --git a/src/app/keymaps/atom.cson b/src/app/keymaps/atom.cson index 97c080d26..2d1d6c01e 100644 --- a/src/app/keymaps/atom.cson +++ b/src/app/keymaps/atom.cson @@ -28,6 +28,7 @@ 'meta--': 'window:decrease-font-size' 'ctrl-w w': 'window:focus-next-pane' 'ctrl-tab': 'window:focus-next-pane' + 'ctrl-meta-f': 'window:toggle-full-screen' 'alt-meta-i': 'toggle-dev-tools' diff --git a/src/app/window.coffee b/src/app/window.coffee index 5158c77d6..1bea3a6d9 100644 --- a/src/app/window.coffee +++ b/src/app/window.coffee @@ -28,6 +28,7 @@ windowAdditions = $(window).on 'core:close', => @close() $(window).command 'window:close', => @close() + $(window).command 'window:toggle-full-screen', => atom.toggleFullScreen() $(window).on 'focus', -> $("body").removeClass('is-blurred') $(window).on 'blur', -> $("body").addClass('is-blurred') From 7ecafb1594137806217e7ec0bcd5d2adb4921e10 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 5 Feb 2013 10:04:37 -0800 Subject: [PATCH 24/32] Don't include tag prefix and suffix Just include the tag name in the symbols view instead of the lengthy namespace prefix and signature suffix. Refs #134 --- .../symbols-view/src/tag-generator.coffee | 35 +++---------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/src/packages/symbols-view/src/tag-generator.coffee b/src/packages/symbols-view/src/tag-generator.coffee index bcc958bb4..7517d4dea 100644 --- a/src/packages/symbols-view/src/tag-generator.coffee +++ b/src/packages/symbols-view/src/tag-generator.coffee @@ -6,40 +6,13 @@ class TagGenerator constructor: (@path, @callback) -> - parsePrefix: (section = "") -> - if section.indexOf('class:') is 0 - section.substring(6) - else if section.indexOf('namespace:') is 0 - section.substring(10) - else if section.indexOf('file:') is 0 - section.substring(5) - else if section.indexOf('signature:') is 0 - section.substring(10) - else if section.indexOf('struct:') is 0 - section.substring(7) - else - section - parseTagLine: (line) -> sections = line.split('\t') - return null if sections.length < 4 - - label = sections[0] - line = parseInt(sections[2]) - 1 - if sections.length > 5 - if prefix = @parsePrefix(sections[4]) - label = "#{prefix}::#{label}" - if suffix = @parsePrefix(sections[5]) - label = "#{label}#{suffix}" + if sections.length > 3 + position: new Point(parseInt(sections[2]) - 1) + name: sections[0] else - if suffix = @parsePrefix(sections[4]) - label = "#{label}#{suffix}" - - tag = - position: new Point(line, 0) - name: label - - return tag + null generate: -> options = From 22770bd66387b54838338dbe938861ccf618eac3 Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Tue, 5 Feb 2013 10:53:35 -0800 Subject: [PATCH 25/32] add onBlur and onFocus events for the window This allows us to simulate those events and test for them easier --- spec/app/window-spec.coffee | 3 ++- src/app/window.coffee | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/spec/app/window-spec.coffee b/spec/app/window-spec.coffee index 6bce6737c..2fbff2c40 100644 --- a/spec/app/window-spec.coffee +++ b/spec/app/window-spec.coffee @@ -15,10 +15,11 @@ describe "Window", -> describe "window is loaded", -> it "doesn't have .is-blurred on the body tag", -> + $(window).trigger 'window:focus' expect($("body").hasClass("is-blurred")).toBe false it "does have .is-blurred on the window blur event", -> - $(window).blur() + $(window).trigger 'window:blur' expect($("body").hasClass("is-blurred")).toBe true describe ".close()", -> diff --git a/src/app/window.coffee b/src/app/window.coffee index 5158c77d6..ef2902c9f 100644 --- a/src/app/window.coffee +++ b/src/app/window.coffee @@ -28,8 +28,12 @@ windowAdditions = $(window).on 'core:close', => @close() $(window).command 'window:close', => @close() - $(window).on 'focus', -> $("body").removeClass('is-blurred') - $(window).on 'blur', -> $("body").addClass('is-blurred') + + $(window).on 'window:focus', onFocus + $(window).on 'window:blur', onBlur + + $(window).on 'focus', -> $(@).trigger 'window:focus' + $(window).on 'blur', -> $(@).trigger 'window:blur' # This method is intended only to be run when starting a normal application # Note: RootView assigns itself on window on initialization so that @@ -102,6 +106,13 @@ windowAdditions = onerror: -> atom.showDevTools() + onFocus: (event) => + console.log 'focused' + $('body').removeClass 'is-blurred' + + onBlur: (event) => + $('body').addClass 'is-blurred' + measure: (description, fn) -> start = new Date().getTime() value = fn() From 44df1460346eb7e1afdccfa7e32a3b070033eb8c Mon Sep 17 00:00:00 2001 From: Justin Palmer Date: Tue, 5 Feb 2013 11:00:01 -0800 Subject: [PATCH 26/32] remove console debug line --- src/app/window.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/window.coffee b/src/app/window.coffee index ef2902c9f..1a707f905 100644 --- a/src/app/window.coffee +++ b/src/app/window.coffee @@ -107,7 +107,6 @@ windowAdditions = atom.showDevTools() onFocus: (event) => - console.log 'focused' $('body').removeClass 'is-blurred' onBlur: (event) => From 65927ea0cf0beb60e4c3104faf9404778896c9b8 Mon Sep 17 00:00:00 2001 From: Justin Palmer & Nathan Sobo Date: Tue, 5 Feb 2013 12:03:56 -0800 Subject: [PATCH 27/32] fix window blur and focus events --- .pairs | 1 + spec/app/window-spec.coffee | 22 ++++++++++++++++------ src/app/window.coffee | 14 ++++---------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/.pairs b/.pairs index c939edd3c..ec4f2417c 100644 --- a/.pairs +++ b/.pairs @@ -5,6 +5,7 @@ pairs: ks: Kevin Sawicki; kevin jc: Jerry Cheung; jerry bl: Brian Lopez; brian + jp: Justin Palmer; justin email: domain: github.com #global: true diff --git a/spec/app/window-spec.coffee b/spec/app/window-spec.coffee index 2fbff2c40..25855e6de 100644 --- a/spec/app/window-spec.coffee +++ b/spec/app/window-spec.coffee @@ -13,14 +13,24 @@ describe "Window", -> atom.setRootViewStateForPath(rootView.project.getPath(), null) $(window).off 'beforeunload' - describe "window is loaded", -> + describe "when the window is loaded", -> it "doesn't have .is-blurred on the body tag", -> - $(window).trigger 'window:focus' - expect($("body").hasClass("is-blurred")).toBe false + expect($("body")).not.toHaveClass("is-blurred") - it "does have .is-blurred on the window blur event", -> - $(window).trigger 'window:blur' - expect($("body").hasClass("is-blurred")).toBe true + fdescribe "when the window is blurred", -> + beforeEach -> + $(window).trigger 'blur' + + afterEach -> + $('body').removeClass('is-blurred') + + it "adds the .is-blurred class on the body", -> + expect($("body")).toHaveClass("is-blurred") + + describe "when the window is focused again", -> + it "removes the .is-blurred class from the body", -> + $(window).trigger 'focus' + expect($("body")).not.toHaveClass("is-blurred") describe ".close()", -> it "is triggered by the 'core:close' event", -> diff --git a/src/app/window.coffee b/src/app/window.coffee index 1a707f905..cc465aa47 100644 --- a/src/app/window.coffee +++ b/src/app/window.coffee @@ -29,11 +29,11 @@ windowAdditions = $(window).on 'core:close', => @close() $(window).command 'window:close', => @close() - $(window).on 'window:focus', onFocus - $(window).on 'window:blur', onBlur + $(window).on 'focus', -> + $('body').removeClass 'is-blurred' - $(window).on 'focus', -> $(@).trigger 'window:focus' - $(window).on 'blur', -> $(@).trigger 'window:blur' + $(window).on 'blur', -> + $('body').addClass 'is-blurred' # This method is intended only to be run when starting a normal application # Note: RootView assigns itself on window on initialization so that @@ -106,12 +106,6 @@ windowAdditions = onerror: -> atom.showDevTools() - onFocus: (event) => - $('body').removeClass 'is-blurred' - - onBlur: (event) => - $('body').addClass 'is-blurred' - measure: (description, fn) -> start = new Date().getTime() value = fn() From ad3c18077cdb693f80a101436d785494e7ec71ea Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 5 Feb 2013 12:02:02 -0800 Subject: [PATCH 28/32] Compare against EOF position when clipping Previously the column could potentially be set to zero since a Math.min comparison was used for the length of an already adjusted row. --- spec/app/buffer-spec.coffee | 14 ++++++++++++++ src/app/buffer.coffee | 16 +++++++++------- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/spec/app/buffer-spec.coffee b/spec/app/buffer-spec.coffee index b13c2b7c2..2a1eaa30c 100644 --- a/spec/app/buffer-spec.coffee +++ b/spec/app/buffer-spec.coffee @@ -889,3 +889,17 @@ describe 'Buffer', -> buffer.setText("\ninitialtext") buffer.append("hello\n1\r\n2\n") expect(buffer.getText()).toBe "\ninitialtexthello\n1\n2\n" + + describe ".clipPosition(position)", -> + describe "when the position is before the start of the buffer", -> + it "returns the first position in the buffer", -> + expect(buffer.clipPosition([-1,0])).toEqual [0,0] + expect(buffer.clipPosition([0,-1])).toEqual [0,0] + expect(buffer.clipPosition([-1,-1])).toEqual [0,0] + + describe "when the position is after the end of the buffer", -> + it "returns the last position in the buffer", -> + buffer.setText('some text') + expect(buffer.clipPosition([1, 0])).toEqual [0,9] + expect(buffer.clipPosition([0,10])).toEqual [0,9] + expect(buffer.clipPosition([10,Infinity])).toEqual [0,9] diff --git a/src/app/buffer.coffee b/src/app/buffer.coffee index db7de2e75..62511d2f9 100644 --- a/src/app/buffer.coffee +++ b/src/app/buffer.coffee @@ -212,13 +212,15 @@ class Buffer range clipPosition: (position) -> - { row, column } = Point.fromObject(position) - row = 0 if row < 0 - column = 0 if column < 0 - row = Math.min(@getLastRow(), row) - column = Math.min(@lineLengthForRow(row), column) - - new Point(row, column) + position = Point.fromObject(position) + eofPosition = @getEofPosition() + if position.isGreaterThan(eofPosition) + eofPosition + else + row = Math.max(position.row, 0) + column = Math.max(position.column, 0) + column = Math.min(@lineLengthForRow(row), column) + new Point(row, column) clipRange: (range) -> range = Range.fromObject(range) From 8de45ccc21f15a1af651bd1569a2d08ddc65c018 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 5 Feb 2013 12:16:50 -0800 Subject: [PATCH 29/32] Bind meta-D to duplicate line below Refs #134 --- spec/app/editor-spec.coffee | 43 +++++++++++++++++++++++++++++++++++++ src/app/edit-session.coffee | 22 +++++++++++++++++++ src/app/editor.coffee | 2 ++ src/app/keymaps/editor.cson | 1 + 4 files changed, 68 insertions(+) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index cf4524393..25620a25e 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -2523,3 +2523,46 @@ describe "Editor", -> 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) {' + + describe "when editor:duplicate-line is triggered", -> + describe "where there is no selection", -> + describe "when the cursor isn't on a folded line", -> + it "duplicates the current line below and moves the cursor down one row", -> + editor.setCursorBufferPosition([0, 5]) + editor.trigger 'editor:duplicate-line' + expect(buffer.lineForRow(0)).toBe 'var quicksort = function () {' + expect(buffer.lineForRow(1)).toBe 'var quicksort = function () {' + expect(editor.getCursorBufferPosition()).toEqual [1, 5] + + describe "when the cursor is on a folded line", -> + it "duplicates the entire fold before and moves the cursor to the new fold", -> + editor.setCursorBufferPosition([4]) + editor.foldCurrentRow() + editor.trigger 'editor:duplicate-line' + expect(editor.getCursorScreenPosition()).toEqual [5] + expect(editor.isFoldedAtScreenRow(4)).toBeTruthy() + expect(editor.isFoldedAtScreenRow(5)).toBeTruthy() + expect(buffer.lineForRow(8)).toBe ' while(items.length > 0) {' + expect(buffer.lineForRow(9)).toBe ' current = items.shift();' + expect(buffer.lineForRow(10)).toBe ' current < pivot ? left.push(current) : right.push(current);' + expect(buffer.lineForRow(11)).toBe ' }' + + describe "when the cursor is on the last line and it doesn't have a trailing newline", -> + it "inserts a newline and the duplicated line", -> + editor.moveCursorToBottom() + editor.trigger 'editor:duplicate-line' + expect(buffer.lineForRow(12)).toBe '};' + expect(buffer.lineForRow(13)).toBe '};' + expect(buffer.lineForRow(14)).toBeUndefined() + expect(editor.getCursorBufferPosition()).toEqual [13, 2] + + describe "when the cursor in on the last line and it is only a newline", -> + it "duplicates the current line below and moves the cursor down one row", -> + editor.moveCursorToBottom() + editor.insertNewline() + editor.moveCursorToBottom() + editor.trigger 'editor:duplicate-line' + expect(buffer.lineForRow(13)).toBe '' + expect(buffer.lineForRow(14)).toBe '' + expect(buffer.lineForRow(15)).toBeUndefined() + expect(editor.getCursorBufferPosition()).toEqual [14, 0] diff --git a/src/app/edit-session.coffee b/src/app/edit-session.coffee index 838a13b76..c0df1d6f0 100644 --- a/src/app/edit-session.coffee +++ b/src/app/edit-session.coffee @@ -411,6 +411,28 @@ class EditSession @setSelectedBufferRange(selection.translate([1]), preserveFolds: true) + duplicateLine: -> + return unless @getSelection().isEmpty() + + @transact => + cursorPosition = @getCursorBufferPosition() + cursorRowFolded = @isFoldedAtCursorRow() + if cursorRowFolded + screenRow = @screenPositionForBufferPosition(cursorPosition).row + bufferRange = @bufferRangeForScreenRange([[screenRow], [screenRow + 1]]) + else + bufferRange = new Range([cursorPosition.row], [cursorPosition.row + 1]) + + insertPosition = new Point(bufferRange.end.row) + if insertPosition.row >= @buffer.getLastRow() + @unfoldCurrentRow() if cursorRowFolded + @buffer.append("\n#{@getTextInBufferRange(bufferRange)}") + @foldCurrentRow() if cursorRowFolded + else + @buffer.insert(insertPosition, @getTextInBufferRange(bufferRange)) + + @setCursorScreenPosition(@getCursorScreenPosition().translate([1])) + @foldCurrentRow() if cursorRowFolded mutateSelectedText: (fn) -> @transact => fn(selection) for selection in @getSelections() diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 8d41771c2..a11807bb0 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -186,6 +186,7 @@ class Editor extends View 'editor:copy-path': @copyPathToPasteboard 'editor:move-line-up': @moveLineUp 'editor:move-line-down': @moveLineDown + 'editor:duplicate-line': @duplicateLine documentation = {} for name, method of editorBindings @@ -209,6 +210,7 @@ class Editor extends View moveCursorToEndOfLine: -> @activeEditSession.moveCursorToEndOfLine() moveLineUp: -> @activeEditSession.moveLineUp() moveLineDown: -> @activeEditSession.moveLineDown() + duplicateLine: -> @activeEditSession.duplicateLine() 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 4c977b698..fdccfd939 100644 --- a/src/app/keymaps/editor.cson +++ b/src/app/keymaps/editor.cson @@ -40,3 +40,4 @@ 'ctrl-C': 'editor:copy-path' 'ctrl-meta-up': 'editor:move-line-up' 'ctrl-meta-down': 'editor:move-line-down' + 'meta-D': 'editor:duplicate-line' From ba811c411951225a55db2aec2003a3372123ccad Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 5 Feb 2013 12:59:26 -0800 Subject: [PATCH 30/32] Un-f a window spec --- spec/app/window-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/app/window-spec.coffee b/spec/app/window-spec.coffee index 25855e6de..cd26fe88a 100644 --- a/spec/app/window-spec.coffee +++ b/spec/app/window-spec.coffee @@ -17,7 +17,7 @@ describe "Window", -> it "doesn't have .is-blurred on the body tag", -> expect($("body")).not.toHaveClass("is-blurred") - fdescribe "when the window is blurred", -> + describe "when the window is blurred", -> beforeEach -> $(window).trigger 'blur' From 17825edf66e29d7096cc04de4566d5e2740faf0e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 5 Feb 2013 13:12:54 -0800 Subject: [PATCH 31/32] Use off() instead of unbind() unbind() is so pre-jQuery 1.7 --- src/app/window.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/window.coffee b/src/app/window.coffee index 1bea3a6d9..4b734fd6a 100644 --- a/src/app/window.coffee +++ b/src/app/window.coffee @@ -52,8 +52,8 @@ windowAdditions = atom.setWindowState('pathToOpen', @rootView.project.getPath()) @rootView.deactivate() @rootView = null - $(window).unbind('focus') - $(window).unbind('blur') + $(window).off('focus') + $(window).off('blur') $(window).off('before') setUpKeymap: -> From 3e84e9886c77d386517f1b69f4b91c5acf768bb2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 5 Feb 2013 13:16:20 -0800 Subject: [PATCH 32/32] Break out event handler setup into separate method This mirrors the keymap setup method and allows specs to reattach handlers after calling shutdown() --- spec/app/window-spec.coffee | 1 + src/app/window.coffee | 2 ++ 2 files changed, 3 insertions(+) diff --git a/spec/app/window-spec.coffee b/spec/app/window-spec.coffee index cd26fe88a..1c166db8f 100644 --- a/spec/app/window-spec.coffee +++ b/spec/app/window-spec.coffee @@ -5,6 +5,7 @@ describe "Window", -> [rootView] = [] beforeEach -> + window.setUpEventHandlers() window.attachRootView(require.resolve('fixtures')) rootView = window.rootView diff --git a/src/app/window.coffee b/src/app/window.coffee index 4b734fd6a..15f7c319e 100644 --- a/src/app/window.coffee +++ b/src/app/window.coffee @@ -25,7 +25,9 @@ windowAdditions = @syntax = new Syntax @setUpKeymap() @pasteboard = new Pasteboard + @setUpEventHandlers() + setUpEventHandlers: -> $(window).on 'core:close', => @close() $(window).command 'window:close', => @close() $(window).command 'window:toggle-full-screen', => atom.toggleFullScreen()