From 63b9a4b179cedacd9e0bdc4b118a73b08a657943 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 08:51:16 -0800 Subject: [PATCH 01/30] Kill wrap-around in command panel preview list Jumping from top to bottom can be still done using meta-up and meta-down. --- .../spec/command-panel-spec.coffee | 17 ++--------------- .../command-panel/src/preview-list.coffee | 10 ++-------- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/src/packages/command-panel/spec/command-panel-spec.coffee b/src/packages/command-panel/spec/command-panel-spec.coffee index f4dc193ef..246302faf 100644 --- a/src/packages/command-panel/spec/command-panel-spec.coffee +++ b/src/packages/command-panel/spec/command-panel-spec.coffee @@ -405,28 +405,15 @@ describe "CommandPanel", -> previewList.trigger 'core:move-down' expect(previewList.scrollTop()).toBe 0 - it "wraps around when the list is at the beginning or end", -> - rootView.attachToDom() - expect(previewList.find('li.operation:eq(0)')).toHaveClass 'selected' - expect(previewList.getSelectedOperation()).toBe previewList.getOperations()[0] - - previewList.trigger 'core:move-up' - expect(previewList.find('li.operation:last')).toHaveClass 'selected' - expect(previewList.getSelectedOperation()).toBe _.last(previewList.getOperations()) - - previewList.trigger 'core:move-down' - expect(previewList.find('li.operation:eq(0)')).toHaveClass 'selected' - expect(previewList.getSelectedOperation()).toBe previewList.getOperations()[0] - it "doesn't bubble up the event and the command panel text doesn't change", -> rootView.attachToDom() commandPanel.miniEditor.setText "command" previewList.focus() previewList.trigger 'core:move-up' - expect(previewList.find('li.operation:last')).toHaveClass 'selected' + expect(previewList.find('li.operation:eq(0)')).toHaveClass 'selected' expect(commandPanel.miniEditor.getText()).toBe 'command' previewList.trigger 'core:move-down' - expect(previewList.find('li.operation:eq(0)')).toHaveClass 'selected' + expect(previewList.find('li.operation:eq(1)')).toHaveClass 'selected' expect(commandPanel.miniEditor.getText()).toBe 'command' describe "when move-to-top and move-to-bottom are triggered on the preview list", -> diff --git a/src/packages/command-panel/src/preview-list.coffee b/src/packages/command-panel/src/preview-list.coffee index 44280eac5..af2ea5479 100644 --- a/src/packages/command-panel/src/preview-list.coffee +++ b/src/packages/command-panel/src/preview-list.coffee @@ -56,16 +56,10 @@ class PreviewList extends ScrollView lineNumbers.width(maxWidth) selectNextOperation: -> - if @selectedOperationIndex is @operations.length - 1 - @setSelectedOperationIndex(0) - else - @setSelectedOperationIndex(@selectedOperationIndex + 1) + @setSelectedOperationIndex(@selectedOperationIndex + 1) selectPreviousOperation: -> - if @selectedOperationIndex is 0 - @setSelectedOperationIndex(@operations.length - 1) - else - @setSelectedOperationIndex(@selectedOperationIndex - 1) + @setSelectedOperationIndex(@selectedOperationIndex - 1) setSelectedOperationIndex: (index, scrollToOperation=true) -> index = Math.max(0, index) From 0f314f573b6c8bcd10aec9ef8f3148a891af1805 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 09:23:18 -0800 Subject: [PATCH 02/30] Add match and file count to command panel preview --- .../command-panel/spec/command-panel-spec.coffee | 10 ++++++++-- .../command-panel/src/command-panel-view.coffee | 6 ++++++ src/packages/command-panel/src/preview-list.coffee | 3 +++ themes/Atom - Dark/command-panel.css | 7 +++++++ themes/Atom - Light/command-panel.css | 7 +++++++ 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/packages/command-panel/spec/command-panel-spec.coffee b/src/packages/command-panel/spec/command-panel-spec.coffee index 246302faf..557b21444 100644 --- a/src/packages/command-panel/spec/command-panel-spec.coffee +++ b/src/packages/command-panel/spec/command-panel-spec.coffee @@ -180,17 +180,19 @@ describe "CommandPanel", -> expect(commandPanel.hasParent()).toBeTruthy() describe "when the mini editor is focused", -> - it "retains focus on the mini editor and does not show the preview list", -> + it "retains focus on the mini editor and does not show the preview list or preview count", -> expect(commandPanel.miniEditor.isFocused).toBeTruthy() rootView.trigger 'command-panel:toggle-preview' expect(commandPanel.previewList).toBeHidden() + expect(commandPanel.previewCount).toBeHidden() expect(commandPanel.miniEditor.isFocused).toBeTruthy() describe "when the mini editor is not focused", -> - it "focuses the mini editor and does not show the preview list", -> + it "focuses the mini editor and does not show the preview list or preview count", -> rootView.focus() rootView.trigger 'command-panel:toggle-preview' expect(commandPanel.previewList).toBeHidden() + expect(commandPanel.previewCount).toBeHidden() expect(commandPanel.miniEditor.isFocused).toBeTruthy() describe "when the command panel is not visible", -> @@ -377,6 +379,10 @@ describe "CommandPanel", -> rootView.trigger 'command-panel:toggle' waitsForPromise -> commandPanel.execute('X x/sort/') + it "displays the number of files and operations", -> + rootView.attachToDom() + expect(commandPanel.previewCount.text()).toBe '17 matches in 4 files' + describe "when move-down and move-up are triggered on the preview list", -> it "selects the next/previous operation (if there is one), and scrolls the list if needed", -> rootView.attachToDom() diff --git a/src/packages/command-panel/src/command-panel-view.coffee b/src/packages/command-panel/src/command-panel-view.coffee index 5e212440c..7ccb74a48 100644 --- a/src/packages/command-panel/src/command-panel-view.coffee +++ b/src/packages/command-panel/src/command-panel-view.coffee @@ -24,6 +24,7 @@ class CommandPanelView extends View @content: (rootView) -> @div class: 'command-panel tool-panel', => + @div outlet: 'previewCount', class: 'preview-count' @subview 'previewList', new PreviewList(rootView) @ul class: 'error-messages', outlet: 'errorMessages' @div class: 'prompt-and-editor', => @@ -48,6 +49,7 @@ class CommandPanelView extends View @command 'core:move-down', => @navigateForwardInHistory() @previewList.hide() + @previewCount.hide() @errorMessages.hide() @prompt.iconSize(@miniEditor.fontSize) @@ -73,12 +75,14 @@ class CommandPanelView extends View togglePreview: -> if @previewList.is(':focus') @previewList.hide() + @previewCount.hide() @detach() @rootView.focus() else @attach() unless @hasParent() if @previewList.hasOperations() @previewList.show().focus() + @previewCount.show() else @miniEditor.focus() @@ -94,6 +98,7 @@ class CommandPanelView extends View detach: -> @rootView.focus() @previewList.hide() + @previewCount.hide() super escapedCommand: -> @@ -115,6 +120,7 @@ class CommandPanelView extends View else if operationsToPreview?.length @previewList.populate(operationsToPreview) @previewList.focus() + @previewCount.text("#{_.pluralize(operationsToPreview.length, 'match', 'matches')} in #{_.pluralize(@previewList.getPathCount(), 'file')}").show() else @detach() catch error diff --git a/src/packages/command-panel/src/preview-list.coffee b/src/packages/command-panel/src/preview-list.coffee index af2ea5479..0fd4541e1 100644 --- a/src/packages/command-panel/src/preview-list.coffee +++ b/src/packages/command-panel/src/preview-list.coffee @@ -84,6 +84,9 @@ class PreviewList extends ScrollView @rootView.focus() false + getPathCount: -> + _.keys(_.groupBy(@operations, (operation) -> operation.getPath())).length + getOperations: -> new Array(@operations...) diff --git a/themes/Atom - Dark/command-panel.css b/themes/Atom - Dark/command-panel.css index 8f4a6e405..116bb2baf 100644 --- a/themes/Atom - Dark/command-panel.css +++ b/themes/Atom - Dark/command-panel.css @@ -15,6 +15,13 @@ cursor: default; } +.command-panel .preview-count { + font-size: 11px; + color: #969696; + text-align: right; + padding-bottom: 1px; +} + .command-panel .preview-list li.selected, .command-panel .preview-list li.operation:hover { background-color: rgba(255, 255, 255, .13); } diff --git a/themes/Atom - Light/command-panel.css b/themes/Atom - Light/command-panel.css index 5344b859d..f9e15c3af 100644 --- a/themes/Atom - Light/command-panel.css +++ b/themes/Atom - Light/command-panel.css @@ -16,6 +16,13 @@ border: 1px solid #989898; } +.command-panel .preview-count { + font-size: 11px; + color: #333; + text-align: right; + padding-bottom: 1px; +} + .command-panel .preview-list li.selected, .command-panel .preview-list li.operation:hover { background-color: rgba(255, 255, 255, .6); } From d1c6caabd6e45db682c2889c6e04a4066b088c81 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki & Nathan Sobo Date: Thu, 10 Jan 2013 11:14:23 -0800 Subject: [PATCH 03/30] Add package to create a Gist from the editor --- src/packages/gists/index.coffee | 1 + src/packages/gists/keymaps/gists.cson | 2 + src/packages/gists/lib/gists.coffee | 19 ++++++++++ src/packages/gists/spec/gists-spec.coffee | 45 +++++++++++++++++++++++ 4 files changed, 67 insertions(+) create mode 100644 src/packages/gists/index.coffee create mode 100644 src/packages/gists/keymaps/gists.cson create mode 100644 src/packages/gists/lib/gists.coffee create mode 100644 src/packages/gists/spec/gists-spec.coffee diff --git a/src/packages/gists/index.coffee b/src/packages/gists/index.coffee new file mode 100644 index 000000000..689bcbeae --- /dev/null +++ b/src/packages/gists/index.coffee @@ -0,0 +1 @@ +module.exports = require './lib/gists' diff --git a/src/packages/gists/keymaps/gists.cson b/src/packages/gists/keymaps/gists.cson new file mode 100644 index 000000000..fa7699100 --- /dev/null +++ b/src/packages/gists/keymaps/gists.cson @@ -0,0 +1,2 @@ +'body': + 'alt-meta-g': 'gist:create' diff --git a/src/packages/gists/lib/gists.coffee b/src/packages/gists/lib/gists.coffee new file mode 100644 index 000000000..ee5591988 --- /dev/null +++ b/src/packages/gists/lib/gists.coffee @@ -0,0 +1,19 @@ +$ = require 'jquery' + +module.exports = + activate: (rootView) -> + rootView.command 'gist:create', '.editor', (e) => + @createGist(e.currentTargetView()) + + createGist: (editor) -> + gist = { public: false, files: {} } + gist.files[editor.getBuffer().getBaseName()] = + content: editor.getSelectedText() or editor.getText() + + $.ajax + url: 'https://api.github.com/gists' + type: 'POST' + dataType: 'json' + contentType: 'application/json; charset=UTF-8' + data: JSON.stringify(gist) + success: (response) -> pasteboard.write(response.html_url) diff --git a/src/packages/gists/spec/gists-spec.coffee b/src/packages/gists/spec/gists-spec.coffee new file mode 100644 index 000000000..c4f69c9c7 --- /dev/null +++ b/src/packages/gists/spec/gists-spec.coffee @@ -0,0 +1,45 @@ +RootView = require 'root-view' +$ = require 'jquery' + +describe "Gists package", -> + + [rootView, editor] = [] + + beforeEach -> + rootView = new RootView(fixturesProject.resolve('sample.js')) + atom.loadPackage('gists') + editor = rootView.getActiveEditor() + spyOn($, 'ajax') + + afterEach -> + rootView.deactivate() + + describe "when gist:create is triggered on an editor", -> + + describe "when the editor has no selection", -> + it "creates an Ajax request to api.github.com with the entire buffer contents as the Gist's content", -> + editor.trigger 'gist:create' + expect($.ajax).toHaveBeenCalled() + request = $.ajax.argsForCall[0][0] + expect(request.url).toBe 'https://api.github.com/gists' + expect(request.type).toBe 'POST' + requestData = JSON.parse(request.data) + expect(requestData.public).toBeFalsy() + expect(requestData.files).toEqual 'sample.js': content: editor.getText() + + it "places the created Gist's URL on the clipboard", -> + editor.trigger 'gist:create' + request = $.ajax.argsForCall[0][0] + request.success(html_url: 'https://gist.github.com/1') + expect(pasteboard.read()[0]).toBe 'https://gist.github.com/1' + + describe "when the editor has a selection", -> + beforeEach -> + editor.setSelectedBufferRange [[4, 0], [8, 0]] + + it "creates an Ajax with the selected text as the Gist's content", -> + editor.trigger 'gist:create' + expect($.ajax).toHaveBeenCalled() + request = $.ajax.argsForCall[0][0] + requestData = JSON.parse(request.data) + expect(requestData.files).toEqual 'sample.js': content: editor.getSelectedText() From cffb73bc8d3d39e4ebaf5b87463a8050cd2465bc Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 10 Jan 2013 13:23:59 -0800 Subject: [PATCH 04/30] Show notification that Gist was created --- src/packages/gists/lib/gists.coffee | 8 ++++++- src/packages/gists/spec/gists-spec.coffee | 28 ++++++++++++++++++----- src/packages/gists/stylesheets/gists.css | 11 +++++++++ 3 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 src/packages/gists/stylesheets/gists.css diff --git a/src/packages/gists/lib/gists.coffee b/src/packages/gists/lib/gists.coffee index ee5591988..008c7d48d 100644 --- a/src/packages/gists/lib/gists.coffee +++ b/src/packages/gists/lib/gists.coffee @@ -1,4 +1,5 @@ $ = require 'jquery' +{$$} = require 'space-pen' module.exports = activate: (rootView) -> @@ -16,4 +17,9 @@ module.exports = dataType: 'json' contentType: 'application/json; charset=UTF-8' data: JSON.stringify(gist) - success: (response) -> pasteboard.write(response.html_url) + success: (response) -> + pasteboard.write(response.html_url) + notification = $$ -> + @div "Gist #{response.id} created", class: 'gist-notification' + rootView.append(notification.hide()) + notification.fadeIn().delay(1800).fadeOut(complete: -> $(this).remove()) diff --git a/src/packages/gists/spec/gists-spec.coffee b/src/packages/gists/spec/gists-spec.coffee index c4f69c9c7..91c52a0ba 100644 --- a/src/packages/gists/spec/gists-spec.coffee +++ b/src/packages/gists/spec/gists-spec.coffee @@ -17,21 +17,37 @@ describe "Gists package", -> describe "when gist:create is triggered on an editor", -> describe "when the editor has no selection", -> - it "creates an Ajax request to api.github.com with the entire buffer contents as the Gist's content", -> + [request, originalFxOffValue] = [] + + beforeEach -> + originalFxOffValue = $.fx.off + $.fx.off = true editor.trigger 'gist:create' expect($.ajax).toHaveBeenCalled() request = $.ajax.argsForCall[0][0] + + afterEach -> + $.fx.off = originalFxOffValue + + it "creates an Ajax request to api.github.com with the entire buffer contents as the Gist's content", -> expect(request.url).toBe 'https://api.github.com/gists' expect(request.type).toBe 'POST' requestData = JSON.parse(request.data) expect(requestData.public).toBeFalsy() expect(requestData.files).toEqual 'sample.js': content: editor.getText() - it "places the created Gist's URL on the clipboard", -> - editor.trigger 'gist:create' - request = $.ajax.argsForCall[0][0] - request.success(html_url: 'https://gist.github.com/1') - expect(pasteboard.read()[0]).toBe 'https://gist.github.com/1' + describe "when the server responds successfully", -> + beforeEach -> + request.success(html_url: 'https://gist.github.com/1', id: '1') + + it "places the created Gist's URL on the clipboard", -> + expect(pasteboard.read()[0]).toBe 'https://gist.github.com/1' + + it "flashes that the Gist was created", -> + expect(rootView.find('.gist-notification')).toExist() + expect(rootView.find('.gist-notification').text()).toBe 'Gist 1 created' + advanceClock(2000) + expect(rootView.find('.gist-notification')).not.toExist() describe "when the editor has a selection", -> beforeEach -> diff --git a/src/packages/gists/stylesheets/gists.css b/src/packages/gists/stylesheets/gists.css new file mode 100644 index 000000000..7bb372e2a --- /dev/null +++ b/src/packages/gists/stylesheets/gists.css @@ -0,0 +1,11 @@ +.gist-notification { + position: absolute; + top: 6px; + left: 50%; + margin-left: -5%; + z-index: 99; + padding: 10px; + -webkit-box-shadow: 0px 0px 5px 5px #222; + color: #FFF; + background-color: #444; +} From bdc85bec76ca54f1dd19ad7592fde04f783a8457 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 10 Jan 2013 15:03:41 -0800 Subject: [PATCH 05/30] Add octicon to Gist notification --- src/packages/gists/lib/gists.coffee | 3 ++- src/packages/gists/stylesheets/gists.css | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/packages/gists/lib/gists.coffee b/src/packages/gists/lib/gists.coffee index 008c7d48d..68c86d5f6 100644 --- a/src/packages/gists/lib/gists.coffee +++ b/src/packages/gists/lib/gists.coffee @@ -20,6 +20,7 @@ module.exports = success: (response) -> pasteboard.write(response.html_url) notification = $$ -> - @div "Gist #{response.id} created", class: 'gist-notification' + @div class: 'gist-notification', => + @span "Gist #{response.id} created" rootView.append(notification.hide()) notification.fadeIn().delay(1800).fadeOut(complete: -> $(this).remove()) diff --git a/src/packages/gists/stylesheets/gists.css b/src/packages/gists/stylesheets/gists.css index 7bb372e2a..5422f4561 100644 --- a/src/packages/gists/stylesheets/gists.css +++ b/src/packages/gists/stylesheets/gists.css @@ -4,8 +4,24 @@ left: 50%; margin-left: -5%; z-index: 99; - padding: 10px; + padding-left: 5px; + padding-right: 10px; -webkit-box-shadow: 0px 0px 5px 5px #222; color: #FFF; background-color: #444; } + +.gist-notification span { + position: relative; + top: -8px; +} + +.gist-notification:before { + font-family: 'Octicons Regular'; + font-size: 32px; + width: 32px; + height: 32px; + margin-right: 5px; + -webkit-font-smoothing: antialiased; + content: "\f08c"; +} From 4a89f4580bfb2707d901488a8ca2ffb1d1e8a7a0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 10:08:00 -0800 Subject: [PATCH 06/30] Make Gists a deferred package --- src/app/deferred-atom-package.coffee | 10 ++++++++-- src/packages/gists/index.coffee | 13 ++++++++++++- src/packages/gists/lib/gists.coffee | 19 ++++++++++++------- src/packages/gists/spec/gists-spec.coffee | 4 ++-- src/packages/gists/stylesheets/gists.css | 16 ++++++++++++---- 5 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/app/deferred-atom-package.coffee b/src/app/deferred-atom-package.coffee index 5b040e3a9..1f328fc02 100644 --- a/src/app/deferred-atom-package.coffee +++ b/src/app/deferred-atom-package.coffee @@ -1,4 +1,5 @@ AtomPackage = require 'atom-package' +_ = require 'underscore' module.exports = class DeferredAtomPackage extends AtomPackage @@ -10,8 +11,13 @@ class DeferredAtomPackage extends AtomPackage activate: (@rootView, @state) -> @instance = null - for event in @loadEvents - @rootView.command event, (e) => @onLoadEvent(e, @getInstance()) + onLoadEvent = (e) => @onLoadEvent(e, @getInstance()) + if _.isArray(@loadEvents) + for event in @loadEvents + @rootView.command(event, onLoadEvent) + else + for event, selector of @loadEvents + @rootView.command(event, selector, onLoadEvent) this deactivate: -> @instance?.deactivate?() diff --git a/src/packages/gists/index.coffee b/src/packages/gists/index.coffee index 689bcbeae..6205cb366 100644 --- a/src/packages/gists/index.coffee +++ b/src/packages/gists/index.coffee @@ -1 +1,12 @@ -module.exports = require './lib/gists' +DeferredAtomPackage = require 'deferred-atom-package' + +module.exports = +class GistsPackage extends DeferredAtomPackage + + loadEvents: + 'gist:create': '.editor' + + instanceClass: 'gists/lib/gists' + + onLoadEvent: (event, instance) -> + instance.createGist(event.currentTargetView()) diff --git a/src/packages/gists/lib/gists.coffee b/src/packages/gists/lib/gists.coffee index 68c86d5f6..434603636 100644 --- a/src/packages/gists/lib/gists.coffee +++ b/src/packages/gists/lib/gists.coffee @@ -2,9 +2,11 @@ $ = require 'jquery' {$$} = require 'space-pen' module.exports = - activate: (rootView) -> - rootView.command 'gist:create', '.editor', (e) => - @createGist(e.currentTargetView()) +class Gists + + @activate: (rootView) -> new Gists(rootView) + + constructor: (@rootView) -> createGist: (editor) -> gist = { public: false, files: {} } @@ -17,10 +19,13 @@ module.exports = dataType: 'json' contentType: 'application/json; charset=UTF-8' data: JSON.stringify(gist) - success: (response) -> + success: (response) => pasteboard.write(response.html_url) notification = $$ -> @div class: 'gist-notification', => - @span "Gist #{response.id} created" - rootView.append(notification.hide()) - notification.fadeIn().delay(1800).fadeOut(complete: -> $(this).remove()) + @div class: 'message-area', => + @span "Gist #{response.id} created", class: 'message' + @br() + @span "The url is on your clipboard", class: 'clipboard' + @rootView.append(notification.hide()) + notification.fadeIn().delay(2000).fadeOut(complete: -> $(this).remove()) diff --git a/src/packages/gists/spec/gists-spec.coffee b/src/packages/gists/spec/gists-spec.coffee index 91c52a0ba..64227744a 100644 --- a/src/packages/gists/spec/gists-spec.coffee +++ b/src/packages/gists/spec/gists-spec.coffee @@ -7,7 +7,7 @@ describe "Gists package", -> beforeEach -> rootView = new RootView(fixturesProject.resolve('sample.js')) - atom.loadPackage('gists') + atom.loadPackage('gists').getInstance() editor = rootView.getActiveEditor() spyOn($, 'ajax') @@ -45,7 +45,7 @@ describe "Gists package", -> it "flashes that the Gist was created", -> expect(rootView.find('.gist-notification')).toExist() - expect(rootView.find('.gist-notification').text()).toBe 'Gist 1 created' + expect(rootView.find('.gist-notification .message').text()).toBe 'Gist 1 created' advanceClock(2000) expect(rootView.find('.gist-notification')).not.toExist() diff --git a/src/packages/gists/stylesheets/gists.css b/src/packages/gists/stylesheets/gists.css index 5422f4561..0209ce3e3 100644 --- a/src/packages/gists/stylesheets/gists.css +++ b/src/packages/gists/stylesheets/gists.css @@ -7,13 +7,21 @@ padding-left: 5px; padding-right: 10px; -webkit-box-shadow: 0px 0px 5px 5px #222; - color: #FFF; + color: #BBB; background-color: #444; } -.gist-notification span { - position: relative; - top: -8px; +.gist-notification .message-area { + float: right; + padding-top: 11px; +} + +.gist-notification .message { + font-size: 13px; +} + +.gist-notification .clipboard { + font-size: 11px; } .gist-notification:before { From 73aab4f49a802527bc441b57ab659815adbe559c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 10:10:19 -0800 Subject: [PATCH 07/30] Move gists stylesheet to themes --- themes/Atom - Dark/gists.css | 35 +++++++++++++++++++ .../Atom - Light}/gists.css | 0 2 files changed, 35 insertions(+) create mode 100644 themes/Atom - Dark/gists.css rename {src/packages/gists/stylesheets => themes/Atom - Light}/gists.css (100%) diff --git a/themes/Atom - Dark/gists.css b/themes/Atom - Dark/gists.css new file mode 100644 index 000000000..dde2dbd25 --- /dev/null +++ b/themes/Atom - Dark/gists.css @@ -0,0 +1,35 @@ +.gist-notification { + position: absolute; + top: 6px; + left: 50%; + margin-left: -5%; + z-index: 99; + padding-left: 5px; + padding-right: 10px; + -webkit-box-shadow: 0px 0px 5px 5px #222; + color: #BBB; + background-color: #333; +} + +.gist-notification .message-area { + float: right; + padding-top: 11px; +} + +.gist-notification .message { + font-size: 13px; +} + +.gist-notification .clipboard { + font-size: 11px; +} + +.gist-notification:before { + font-family: 'Octicons Regular'; + font-size: 32px; + width: 32px; + height: 32px; + margin-right: 5px; + -webkit-font-smoothing: antialiased; + content: "\f08c"; +} diff --git a/src/packages/gists/stylesheets/gists.css b/themes/Atom - Light/gists.css similarity index 100% rename from src/packages/gists/stylesheets/gists.css rename to themes/Atom - Light/gists.css From fb4623d5d37c8e5142f89e9c4237adb3fa635220 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 10:28:07 -0800 Subject: [PATCH 08/30] Don't populate list until elements have been set Closes #174 --- spec/app/select-list-spec.coffee | 11 +++++++++++ src/app/select-list.coffee | 2 ++ 2 files changed, 13 insertions(+) diff --git a/spec/app/select-list-spec.coffee b/spec/app/select-list-spec.coffee index 01ffeb445..e4e4d32cc 100644 --- a/spec/app/select-list-spec.coffee +++ b/spec/app/select-list-spec.coffee @@ -59,6 +59,17 @@ describe "SelectList", -> expect(selectList.error).not.toBeVisible() expect(selectList).not.toHaveClass("error") + it "displays no elements until the array has been set on the list", -> + selectList.array = null + selectList.list.empty() + miniEditor.insertText('la') + window.advanceClock(selectList.inputThrottle) + + expect(list.find('li').length).toBe 0 + expect(selectList).not.toHaveClass("error") + selectList.setArray(array) + expect(list.find('li').length).toBe 2 + describe "when core:move-up / core:move-down are triggered on the miniEditor", -> it "selects the previous / next item in the list, or wraps around to the other side", -> expect(list.find('li:first')).toHaveClass 'selected' diff --git a/src/app/select-list.coffee b/src/app/select-list.coffee index 020aaf734..5bdb3258d 100644 --- a/src/app/select-list.coffee +++ b/src/app/select-list.coffee @@ -62,6 +62,8 @@ class SelectList extends View @loading.text(message).show() populateList: -> + return unless @array? + filterQuery = @miniEditor.getText() if filterQuery.length filteredArray = fuzzyFilter(@array, filterQuery, key: @filterKey) From 54eabce9ab7ac4349023659fbc63761172f2dd2c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 10:30:36 -0800 Subject: [PATCH 09/30] Switch grammar toggle to meta-L meta-l should be reserved for jump to line --- src/app/keymaps/editor.cson | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/keymaps/editor.cson b/src/app/keymaps/editor.cson index 2f48d27bb..2f6da8a83 100644 --- a/src/app/keymaps/editor.cson +++ b/src/app/keymaps/editor.cson @@ -36,4 +36,4 @@ 'meta-U': 'editor:lower-case' 'alt-meta-w': 'editor:close-other-edit-sessions' 'meta-P': 'editor:close-all-edit-sessions' - 'meta-l': 'editor:select-grammar' + 'meta-L': 'editor:select-grammar' From cb94c712cc9d9d1601aab15d436af576f01be196 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 10:44:14 -0800 Subject: [PATCH 10/30] Add gists stylesheet to package.json --- themes/Atom - Dark/package.json | 3 ++- themes/Atom - Light/package.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/themes/Atom - Dark/package.json b/themes/Atom - Dark/package.json index 4d5c95b40..f494ccd78 100644 --- a/themes/Atom - Dark/package.json +++ b/themes/Atom - Dark/package.json @@ -14,6 +14,7 @@ "command-panel.css", "command-palette.css", "command-logger.css", - "autocomplete.css" + "autocomplete.css", + "gists.css" ] } diff --git a/themes/Atom - Light/package.json b/themes/Atom - Light/package.json index 4d5c95b40..f494ccd78 100644 --- a/themes/Atom - Light/package.json +++ b/themes/Atom - Light/package.json @@ -14,6 +14,7 @@ "command-panel.css", "command-palette.css", "command-logger.css", - "autocomplete.css" + "autocomplete.css", + "gists.css" ] } From e22c8d69f7b01da8c90235e84ec52a1f105d90ec Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 11:22:29 -0800 Subject: [PATCH 11/30] Add jump to line bound to meta-l Closes #176 --- src/packages/jump-to-line/index.coffee | 12 +++++ .../jump-to-line/keymaps/jump-to-line.cson | 6 +++ .../jump-to-line/lib/jump-to-line-view.coffee | 52 +++++++++++++++++++ .../spec/jump-to-line-spec.coffee | 41 +++++++++++++++ themes/Atom - Dark/jump-to-line.css | 27 ++++++++++ themes/Atom - Dark/package.json | 3 +- themes/Atom - Light/jump-to-line.css | 27 ++++++++++ themes/Atom - Light/package.json | 3 +- 8 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 src/packages/jump-to-line/index.coffee create mode 100644 src/packages/jump-to-line/keymaps/jump-to-line.cson create mode 100644 src/packages/jump-to-line/lib/jump-to-line-view.coffee create mode 100644 src/packages/jump-to-line/spec/jump-to-line-spec.coffee create mode 100644 themes/Atom - Dark/jump-to-line.css create mode 100644 themes/Atom - Light/jump-to-line.css diff --git a/src/packages/jump-to-line/index.coffee b/src/packages/jump-to-line/index.coffee new file mode 100644 index 000000000..45bc34e46 --- /dev/null +++ b/src/packages/jump-to-line/index.coffee @@ -0,0 +1,12 @@ +DeferredAtomPackage = require 'deferred-atom-package' + +module.exports = +class JumpToLinePackage extends DeferredAtomPackage + + loadEvents: + 'editor:jump-to-line': '.editor' + + instanceClass: 'jump-to-line/lib/jump-to-line-view' + + onLoadEvent: (event, instance) -> + instance.toggle(event.currentTargetView()) diff --git a/src/packages/jump-to-line/keymaps/jump-to-line.cson b/src/packages/jump-to-line/keymaps/jump-to-line.cson new file mode 100644 index 000000000..8a02f09dd --- /dev/null +++ b/src/packages/jump-to-line/keymaps/jump-to-line.cson @@ -0,0 +1,6 @@ +'body': + 'meta-l': 'editor:jump-to-line' +'.jump-to-line .mini.editor input': + 'enter': 'core:confirm', + 'escape': 'core:cancel' + 'meta-w': 'core:cancel' diff --git a/src/packages/jump-to-line/lib/jump-to-line-view.coffee b/src/packages/jump-to-line/lib/jump-to-line-view.coffee new file mode 100644 index 000000000..389b10ec6 --- /dev/null +++ b/src/packages/jump-to-line/lib/jump-to-line-view.coffee @@ -0,0 +1,52 @@ +{View} = require 'space-pen' +Editor = require 'editor' +$ = require 'jquery' +Point = require 'point' + +module.exports = +class JumpToLineView extends View + + @activate: (rootView) -> new JumpToLineView(rootView) + + @content: -> + @div class: 'jump-to-line', => + @subview 'miniEditor', new Editor(mini: true) + @div class: 'message', outlet: 'message' + + initialize: (@rootView) -> + @miniEditor.on 'focusout', => @detach() if @hasParent() + @on 'core:confirm', => @confirm() + @on 'core:cancel', => @detach() if @hasParent() + + @miniEditor.preempt 'textInput', (e) => + false unless e.originalEvent.data.match(/[0-9]/) + + toggle: -> + if @hasParent() + @detach() + else + @attach() + + detach: -> + @miniEditor.setText('') + @previouslyFocusedElement?.focus() + + super + + confirm: -> + lineNumber = @miniEditor.getText() + editor = rootView.getActiveEditor() + + @detach() + + return unless editor and lineNumber.length + position = new Point(parseInt(lineNumber - 1, 0)) + editor.scrollToBufferPosition(position, center: true) + editor.setCursorBufferPosition(position) + editor.moveCursorToFirstCharacterOfLine() + + attach: -> + @previouslyFocusedElement = $(':focus') + @rootView.append(this) + @message.text("Enter a line number 1-#{@editor.getLineCount()}") + @miniEditor.focus() diff --git a/src/packages/jump-to-line/spec/jump-to-line-spec.coffee b/src/packages/jump-to-line/spec/jump-to-line-spec.coffee new file mode 100644 index 000000000..a1e2f1562 --- /dev/null +++ b/src/packages/jump-to-line/spec/jump-to-line-spec.coffee @@ -0,0 +1,41 @@ +RootView = require 'root-view' + +describe 'JumpToLine', -> + [rootView, jumpToLine, editor] = [] + + beforeEach -> + rootView = new RootView(require.resolve('fixtures/sample.js')) + rootView.enableKeymap() + jumpToLine = atom.loadPackage("jump-to-line").getInstance() + editor = rootView.getActiveEditor() + editor.setCursorBufferPosition([1,0]) + + afterEach -> + rootView.remove() + + describe "when entering a line number", -> + it "only allows 0-9 to be entered in the mini editor", -> + expect(jumpToLine.miniEditor.getText()).toBe '' + jumpToLine.miniEditor.textInput 'a' + expect(jumpToLine.miniEditor.getText()).toBe '' + jumpToLine.miniEditor.textInput '40' + expect(jumpToLine.miniEditor.getText()).toBe '40' + + describe "when core:confirm is triggered", -> + describe "when a line number has been entered", -> + it "moves the cursor to the first character of the line", -> + jumpToLine.miniEditor.textInput '3' + jumpToLine.miniEditor.trigger 'core:confirm' + expect(editor.getCursorBufferPosition()).toEqual [2, 4] + + describe "when no line number has been entered", -> + it "closes the view and does not update the cursor position", -> + jumpToLine.miniEditor.trigger 'core:confirm' + expect(jumpToLine.hasParent()).toBeFalsy() + expect(editor.getCursorBufferPosition()).toEqual [1, 0] + + describe "when core:cancel is triggered", -> + it "closes the view and does not update the cursor position", -> + jumpToLine.miniEditor.trigger 'core:cancel' + expect(jumpToLine.hasParent()).toBeFalsy() + expect(editor.getCursorBufferPosition()).toEqual [1, 0] diff --git a/themes/Atom - Dark/jump-to-line.css b/themes/Atom - Dark/jump-to-line.css new file mode 100644 index 000000000..8165f84b1 --- /dev/null +++ b/themes/Atom - Dark/jump-to-line.css @@ -0,0 +1,27 @@ +.jump-to-line { + position: absolute; + width: 200px; + top: 0; + left: 50%; + margin-left: -100px; + box-sizing: border-box; + z-index: 99; + background-color: #484848; + border: 1px solid #444; + color: #d2d2d2; + box-shadow: 0 0 10px #000; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + padding: 5px; + cursor: pointer; +} + +.jump-to-line .editor { + box-sizing: border-box; + padding: 5px; +} + +.jump-to-line .message { + padding-top: 2px; + font-size: 11px; +} diff --git a/themes/Atom - Dark/package.json b/themes/Atom - Dark/package.json index f494ccd78..8840dfa59 100644 --- a/themes/Atom - Dark/package.json +++ b/themes/Atom - Dark/package.json @@ -15,6 +15,7 @@ "command-palette.css", "command-logger.css", "autocomplete.css", - "gists.css" + "gists.css", + "jump-to-line.css" ] } diff --git a/themes/Atom - Light/jump-to-line.css b/themes/Atom - Light/jump-to-line.css new file mode 100644 index 000000000..0aaf6ba67 --- /dev/null +++ b/themes/Atom - Light/jump-to-line.css @@ -0,0 +1,27 @@ +.jump-to-line { + position: absolute; + width: 200px; + top: 0; + left: 50%; + margin-left: -100px; + box-sizing: border-box; + z-index: 99; + background-color: #eeeeee; + border: 1px solid #c6c6c6; + color: #323232; + box-shadow: 0 0 10px #555; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + padding: 5px; + cursor: pointer; +} + +.jump-to-line .editor { + box-sizing: border-box; + padding: 5px; +} + +.jump-to-line .message { + padding-top: 2px; + font-size: 11px; +} diff --git a/themes/Atom - Light/package.json b/themes/Atom - Light/package.json index f494ccd78..8840dfa59 100644 --- a/themes/Atom - Light/package.json +++ b/themes/Atom - Light/package.json @@ -15,6 +15,7 @@ "command-palette.css", "command-logger.css", "autocomplete.css", - "gists.css" + "gists.css", + "jump-to-line.css" ] } From 126d938aeb7a51834f7db38f0b79689d7d8a4029 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 12:43:38 -0800 Subject: [PATCH 12/30] Use active editor from root view instead of ivar --- src/packages/jump-to-line/lib/jump-to-line-view.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/jump-to-line/lib/jump-to-line-view.coffee b/src/packages/jump-to-line/lib/jump-to-line-view.coffee index 389b10ec6..fd8e4e555 100644 --- a/src/packages/jump-to-line/lib/jump-to-line-view.coffee +++ b/src/packages/jump-to-line/lib/jump-to-line-view.coffee @@ -48,5 +48,5 @@ class JumpToLineView extends View attach: -> @previouslyFocusedElement = $(':focus') @rootView.append(this) - @message.text("Enter a line number 1-#{@editor.getLineCount()}") + @message.text("Enter a line number 1-#{@rootView.getActiveEditor().getLineCount()}") @miniEditor.focus() From 90d2e12e62dcbaefaa115297116650d4b5c46848 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 12:44:13 -0800 Subject: [PATCH 13/30] Add spec for editor:jump-to-line event --- src/packages/jump-to-line/spec/jump-to-line-spec.coffee | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/packages/jump-to-line/spec/jump-to-line-spec.coffee b/src/packages/jump-to-line/spec/jump-to-line-spec.coffee index a1e2f1562..0f82c2c7c 100644 --- a/src/packages/jump-to-line/spec/jump-to-line-spec.coffee +++ b/src/packages/jump-to-line/spec/jump-to-line-spec.coffee @@ -13,6 +13,12 @@ describe 'JumpToLine', -> afterEach -> rootView.remove() + describe "when editor:jump-to-line is triggered", -> + it "attaches to the root view", -> + expect(jumpToLine.hasParent()).toBeFalsy() + editor.trigger 'editor:jump-to-line' + expect(jumpToLine.hasParent()).toBeTruthy() + describe "when entering a line number", -> it "only allows 0-9 to be entered in the mini editor", -> expect(jumpToLine.miniEditor.getText()).toBe '' From 58dbddad532f7d22f12f9067191e7abfea974685 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 12:45:20 -0800 Subject: [PATCH 14/30] Trigger attach before verifying confirm/cancel events --- src/packages/jump-to-line/spec/jump-to-line-spec.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/packages/jump-to-line/spec/jump-to-line-spec.coffee b/src/packages/jump-to-line/spec/jump-to-line-spec.coffee index 0f82c2c7c..e00ba8b58 100644 --- a/src/packages/jump-to-line/spec/jump-to-line-spec.coffee +++ b/src/packages/jump-to-line/spec/jump-to-line-spec.coffee @@ -36,12 +36,16 @@ describe 'JumpToLine', -> describe "when no line number has been entered", -> it "closes the view and does not update the cursor position", -> + editor.trigger 'editor:jump-to-line' + expect(jumpToLine.hasParent()).toBeTruthy() jumpToLine.miniEditor.trigger 'core:confirm' expect(jumpToLine.hasParent()).toBeFalsy() expect(editor.getCursorBufferPosition()).toEqual [1, 0] describe "when core:cancel is triggered", -> it "closes the view and does not update the cursor position", -> + editor.trigger 'editor:jump-to-line' + expect(jumpToLine.hasParent()).toBeTruthy() jumpToLine.miniEditor.trigger 'core:cancel' expect(jumpToLine.hasParent()).toBeFalsy() expect(editor.getCursorBufferPosition()).toEqual [1, 0] From 8bf82d3aa1d5594878c2c9568c90f8afe4e84ff2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 12:46:08 -0800 Subject: [PATCH 15/30] Don't detach unless view has parent --- src/packages/jump-to-line/lib/jump-to-line-view.coffee | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/packages/jump-to-line/lib/jump-to-line-view.coffee b/src/packages/jump-to-line/lib/jump-to-line-view.coffee index fd8e4e555..b055a0274 100644 --- a/src/packages/jump-to-line/lib/jump-to-line-view.coffee +++ b/src/packages/jump-to-line/lib/jump-to-line-view.coffee @@ -14,9 +14,9 @@ class JumpToLineView extends View @div class: 'message', outlet: 'message' initialize: (@rootView) -> - @miniEditor.on 'focusout', => @detach() if @hasParent() + @miniEditor.on 'focusout', => @detach() @on 'core:confirm', => @confirm() - @on 'core:cancel', => @detach() if @hasParent() + @on 'core:cancel', => @detach() @miniEditor.preempt 'textInput', (e) => false unless e.originalEvent.data.match(/[0-9]/) @@ -28,6 +28,8 @@ class JumpToLineView extends View @attach() detach: -> + return unless @hasParent() + @miniEditor.setText('') @previouslyFocusedElement?.focus() From 552499994696d1bc8a35c903208e79cec35e12b9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 12:52:10 -0800 Subject: [PATCH 16/30] Rename jump-to-line package to go-to-line --- .../{jump-to-line => go-to-line}/index.coffee | 6 +-- .../keymaps/go-to-line.cson} | 4 +- .../lib/go-to-line-view.coffee} | 6 +-- .../go-to-line/spec/go-to-line-spec.coffee | 51 +++++++++++++++++++ .../spec/jump-to-line-spec.coffee | 51 ------------------- .../{jump-to-line.css => go-to-line.css} | 6 +-- themes/Atom - Dark/package.json | 2 +- .../{jump-to-line.css => go-to-line.css} | 6 +-- themes/Atom - Light/package.json | 2 +- 9 files changed, 67 insertions(+), 67 deletions(-) rename src/packages/{jump-to-line => go-to-line}/index.coffee (54%) rename src/packages/{jump-to-line/keymaps/jump-to-line.cson => go-to-line/keymaps/go-to-line.cson} (55%) rename src/packages/{jump-to-line/lib/jump-to-line-view.coffee => go-to-line/lib/go-to-line-view.coffee} (90%) create mode 100644 src/packages/go-to-line/spec/go-to-line-spec.coffee delete mode 100644 src/packages/jump-to-line/spec/jump-to-line-spec.coffee rename themes/Atom - Dark/{jump-to-line.css => go-to-line.css} (86%) rename themes/Atom - Light/{jump-to-line.css => go-to-line.css} (86%) diff --git a/src/packages/jump-to-line/index.coffee b/src/packages/go-to-line/index.coffee similarity index 54% rename from src/packages/jump-to-line/index.coffee rename to src/packages/go-to-line/index.coffee index 45bc34e46..12601c00e 100644 --- a/src/packages/jump-to-line/index.coffee +++ b/src/packages/go-to-line/index.coffee @@ -1,12 +1,12 @@ DeferredAtomPackage = require 'deferred-atom-package' module.exports = -class JumpToLinePackage extends DeferredAtomPackage +class GoToLinePackage extends DeferredAtomPackage loadEvents: - 'editor:jump-to-line': '.editor' + 'editor:go-to-line': '.editor' - instanceClass: 'jump-to-line/lib/jump-to-line-view' + instanceClass: 'go-to-line/lib/go-to-line-view' onLoadEvent: (event, instance) -> instance.toggle(event.currentTargetView()) diff --git a/src/packages/jump-to-line/keymaps/jump-to-line.cson b/src/packages/go-to-line/keymaps/go-to-line.cson similarity index 55% rename from src/packages/jump-to-line/keymaps/jump-to-line.cson rename to src/packages/go-to-line/keymaps/go-to-line.cson index 8a02f09dd..5686829bd 100644 --- a/src/packages/jump-to-line/keymaps/jump-to-line.cson +++ b/src/packages/go-to-line/keymaps/go-to-line.cson @@ -1,6 +1,6 @@ 'body': - 'meta-l': 'editor:jump-to-line' -'.jump-to-line .mini.editor input': + 'meta-l': 'editor:go-to-line' +'.go-to-line .mini.editor input': 'enter': 'core:confirm', 'escape': 'core:cancel' 'meta-w': 'core:cancel' diff --git a/src/packages/jump-to-line/lib/jump-to-line-view.coffee b/src/packages/go-to-line/lib/go-to-line-view.coffee similarity index 90% rename from src/packages/jump-to-line/lib/jump-to-line-view.coffee rename to src/packages/go-to-line/lib/go-to-line-view.coffee index b055a0274..ce99ece31 100644 --- a/src/packages/jump-to-line/lib/jump-to-line-view.coffee +++ b/src/packages/go-to-line/lib/go-to-line-view.coffee @@ -4,12 +4,12 @@ $ = require 'jquery' Point = require 'point' module.exports = -class JumpToLineView extends View +class GoToLineView extends View - @activate: (rootView) -> new JumpToLineView(rootView) + @activate: (rootView) -> new GoToLineView(rootView) @content: -> - @div class: 'jump-to-line', => + @div class: 'go-to-line', => @subview 'miniEditor', new Editor(mini: true) @div class: 'message', outlet: 'message' diff --git a/src/packages/go-to-line/spec/go-to-line-spec.coffee b/src/packages/go-to-line/spec/go-to-line-spec.coffee new file mode 100644 index 000000000..775bde131 --- /dev/null +++ b/src/packages/go-to-line/spec/go-to-line-spec.coffee @@ -0,0 +1,51 @@ +RootView = require 'root-view' + +describe 'GoToLine', -> + [rootView, goToLine, editor] = [] + + beforeEach -> + rootView = new RootView(require.resolve('fixtures/sample.js')) + rootView.enableKeymap() + goToLine = atom.loadPackage("go-to-line").getInstance() + editor = rootView.getActiveEditor() + editor.setCursorBufferPosition([1,0]) + + afterEach -> + rootView.remove() + + describe "when editor:go-to-line is triggered", -> + it "attaches to the root view", -> + expect(goToLine.hasParent()).toBeFalsy() + editor.trigger 'editor:go-to-line' + expect(goToLine.hasParent()).toBeTruthy() + + describe "when entering a line number", -> + it "only allows 0-9 to be entered in the mini editor", -> + expect(goToLine.miniEditor.getText()).toBe '' + goToLine.miniEditor.textInput 'a' + expect(goToLine.miniEditor.getText()).toBe '' + goToLine.miniEditor.textInput '40' + expect(goToLine.miniEditor.getText()).toBe '40' + + describe "when core:confirm is triggered", -> + describe "when a line number has been entered", -> + it "moves the cursor to the first character of the line", -> + goToLine.miniEditor.textInput '3' + goToLine.miniEditor.trigger 'core:confirm' + expect(editor.getCursorBufferPosition()).toEqual [2, 4] + + describe "when no line number has been entered", -> + it "closes the view and does not update the cursor position", -> + editor.trigger 'editor:go-to-line' + expect(goToLine.hasParent()).toBeTruthy() + goToLine.miniEditor.trigger 'core:confirm' + expect(goToLine.hasParent()).toBeFalsy() + expect(editor.getCursorBufferPosition()).toEqual [1, 0] + + describe "when core:cancel is triggered", -> + it "closes the view and does not update the cursor position", -> + editor.trigger 'editor:go-to-line' + expect(goToLine.hasParent()).toBeTruthy() + goToLine.miniEditor.trigger 'core:cancel' + expect(goToLine.hasParent()).toBeFalsy() + expect(editor.getCursorBufferPosition()).toEqual [1, 0] diff --git a/src/packages/jump-to-line/spec/jump-to-line-spec.coffee b/src/packages/jump-to-line/spec/jump-to-line-spec.coffee deleted file mode 100644 index e00ba8b58..000000000 --- a/src/packages/jump-to-line/spec/jump-to-line-spec.coffee +++ /dev/null @@ -1,51 +0,0 @@ -RootView = require 'root-view' - -describe 'JumpToLine', -> - [rootView, jumpToLine, editor] = [] - - beforeEach -> - rootView = new RootView(require.resolve('fixtures/sample.js')) - rootView.enableKeymap() - jumpToLine = atom.loadPackage("jump-to-line").getInstance() - editor = rootView.getActiveEditor() - editor.setCursorBufferPosition([1,0]) - - afterEach -> - rootView.remove() - - describe "when editor:jump-to-line is triggered", -> - it "attaches to the root view", -> - expect(jumpToLine.hasParent()).toBeFalsy() - editor.trigger 'editor:jump-to-line' - expect(jumpToLine.hasParent()).toBeTruthy() - - describe "when entering a line number", -> - it "only allows 0-9 to be entered in the mini editor", -> - expect(jumpToLine.miniEditor.getText()).toBe '' - jumpToLine.miniEditor.textInput 'a' - expect(jumpToLine.miniEditor.getText()).toBe '' - jumpToLine.miniEditor.textInput '40' - expect(jumpToLine.miniEditor.getText()).toBe '40' - - describe "when core:confirm is triggered", -> - describe "when a line number has been entered", -> - it "moves the cursor to the first character of the line", -> - jumpToLine.miniEditor.textInput '3' - jumpToLine.miniEditor.trigger 'core:confirm' - expect(editor.getCursorBufferPosition()).toEqual [2, 4] - - describe "when no line number has been entered", -> - it "closes the view and does not update the cursor position", -> - editor.trigger 'editor:jump-to-line' - expect(jumpToLine.hasParent()).toBeTruthy() - jumpToLine.miniEditor.trigger 'core:confirm' - expect(jumpToLine.hasParent()).toBeFalsy() - expect(editor.getCursorBufferPosition()).toEqual [1, 0] - - describe "when core:cancel is triggered", -> - it "closes the view and does not update the cursor position", -> - editor.trigger 'editor:jump-to-line' - expect(jumpToLine.hasParent()).toBeTruthy() - jumpToLine.miniEditor.trigger 'core:cancel' - expect(jumpToLine.hasParent()).toBeFalsy() - expect(editor.getCursorBufferPosition()).toEqual [1, 0] diff --git a/themes/Atom - Dark/jump-to-line.css b/themes/Atom - Dark/go-to-line.css similarity index 86% rename from themes/Atom - Dark/jump-to-line.css rename to themes/Atom - Dark/go-to-line.css index 8165f84b1..4ceec81aa 100644 --- a/themes/Atom - Dark/jump-to-line.css +++ b/themes/Atom - Dark/go-to-line.css @@ -1,4 +1,4 @@ -.jump-to-line { +.go-to-line { position: absolute; width: 200px; top: 0; @@ -16,12 +16,12 @@ cursor: pointer; } -.jump-to-line .editor { +.go-to-line .editor { box-sizing: border-box; padding: 5px; } -.jump-to-line .message { +.go-to-line .message { padding-top: 2px; font-size: 11px; } diff --git a/themes/Atom - Dark/package.json b/themes/Atom - Dark/package.json index 8840dfa59..28f90e051 100644 --- a/themes/Atom - Dark/package.json +++ b/themes/Atom - Dark/package.json @@ -16,6 +16,6 @@ "command-logger.css", "autocomplete.css", "gists.css", - "jump-to-line.css" + "go-to-line.css" ] } diff --git a/themes/Atom - Light/jump-to-line.css b/themes/Atom - Light/go-to-line.css similarity index 86% rename from themes/Atom - Light/jump-to-line.css rename to themes/Atom - Light/go-to-line.css index 0aaf6ba67..9f6c3ec8b 100644 --- a/themes/Atom - Light/jump-to-line.css +++ b/themes/Atom - Light/go-to-line.css @@ -1,4 +1,4 @@ -.jump-to-line { +.go-to-line { position: absolute; width: 200px; top: 0; @@ -16,12 +16,12 @@ cursor: pointer; } -.jump-to-line .editor { +.go-to-line .editor { box-sizing: border-box; padding: 5px; } -.jump-to-line .message { +.go-to-line .message { padding-top: 2px; font-size: 11px; } diff --git a/themes/Atom - Light/package.json b/themes/Atom - Light/package.json index 8840dfa59..28f90e051 100644 --- a/themes/Atom - Light/package.json +++ b/themes/Atom - Light/package.json @@ -16,6 +16,6 @@ "command-logger.css", "autocomplete.css", "gists.css", - "jump-to-line.css" + "go-to-line.css" ] } From e919759c58eafd19f11afb9759b53fd0f5909748 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 12:55:12 -0800 Subject: [PATCH 17/30] Rename jump-to-declaration command to go-to-declaration --- src/packages/symbols-view/index.coffee | 6 +++--- src/packages/symbols-view/keymaps/symbols-view.cson | 2 +- .../symbols-view/spec/symbols-view-spec.coffee | 10 +++++----- src/packages/symbols-view/src/symbols-view.coffee | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/packages/symbols-view/index.coffee b/src/packages/symbols-view/index.coffee index c025f58f0..50d9a89c0 100644 --- a/src/packages/symbols-view/index.coffee +++ b/src/packages/symbols-view/index.coffee @@ -6,7 +6,7 @@ class Symbols extends DeferredAtomPackage loadEvents: [ 'symbols-view:toggle-file-symbols' 'symbols-view:toggle-project-symbols' - 'symbols-view:jump-to-declaration' + 'symbols-view:go-to-declaration' ] instanceClass: 'symbols-view/src/symbols-view' @@ -17,5 +17,5 @@ class Symbols extends DeferredAtomPackage instance.toggleFileSymbols() when 'symbols-view:toggle-project-symbols' instance.toggleProjectSymbols() - when 'symbols-view:jump-to-declaration' - instance.jumpToDeclaration() + when 'symbols-view:go-to-declaration' + instance.goToDeclaration() diff --git a/src/packages/symbols-view/keymaps/symbols-view.cson b/src/packages/symbols-view/keymaps/symbols-view.cson index 4a77be68d..1e579abe0 100644 --- a/src/packages/symbols-view/keymaps/symbols-view.cson +++ b/src/packages/symbols-view/keymaps/symbols-view.cson @@ -1,6 +1,6 @@ '.editor': 'meta-j': 'symbols-view:toggle-file-symbols' - 'meta-.': 'symbols-view:jump-to-declaration' + 'meta-.': 'symbols-view:go-to-declaration' 'body': 'meta-J': 'symbols-view:toggle-project-symbols' diff --git a/src/packages/symbols-view/spec/symbols-view-spec.coffee b/src/packages/symbols-view/spec/symbols-view-spec.coffee index 9bfe907bd..89476c8d5 100644 --- a/src/packages/symbols-view/spec/symbols-view-spec.coffee +++ b/src/packages/symbols-view/spec/symbols-view-spec.coffee @@ -126,26 +126,26 @@ describe "SymbolsView", -> generator.generate().done -> expect(tags.length).toBe 0 - describe "jump to declaration", -> + describe "go to declaration", -> it "doesn't move the cursor when no declaration is found", -> rootView.open("tagged.js") editor = rootView.getActiveEditor() editor.setCursorBufferPosition([0,2]) - editor.trigger 'symbols-view:jump-to-declaration' + editor.trigger 'symbols-view:go-to-declaration' expect(editor.getCursorBufferPosition()).toEqual [0,2] it "moves the cursor to the declaration", -> rootView.open("tagged.js") editor = rootView.getActiveEditor() editor.setCursorBufferPosition([6,24]) - editor.trigger 'symbols-view:jump-to-declaration' + editor.trigger 'symbols-view:go-to-declaration' expect(editor.getCursorBufferPosition()).toEqual [2,0] it "displays matches when more than one exists and opens the selected match", -> rootView.open("tagged.js") editor = rootView.getActiveEditor() editor.setCursorBufferPosition([8,14]) - editor.trigger 'symbols-view:jump-to-declaration' + editor.trigger 'symbols-view:go-to-declaration' expect(symbolsView.list.children('li').length).toBe 2 expect(symbolsView).toBeVisible() symbolsView.confirmed(symbolsView.array[0]) @@ -163,7 +163,7 @@ describe "SymbolsView", -> rootView.open("tagged.js") editor = rootView.getActiveEditor() editor.setCursorBufferPosition([8,14]) - editor.trigger 'symbols-view:jump-to-declaration' + editor.trigger 'symbols-view:go-to-declaration' expect(symbolsView.list.children('li').length).toBe 1 expect(symbolsView.list.children('li:first').find('.function-name')).toHaveText 'tagged.js' diff --git a/src/packages/symbols-view/src/symbols-view.coffee b/src/packages/symbols-view/src/symbols-view.coffee index afcd5109e..c0d019132 100644 --- a/src/packages/symbols-view/src/symbols-view.coffee +++ b/src/packages/symbols-view/src/symbols-view.coffee @@ -102,7 +102,7 @@ class SymbolsView extends SelectList for line, index in fs.read(file).split('\n') return new Point(index, 0) if pattern is $.trim(line) - jumpToDeclaration: -> + goToDeclaration: -> editor = @rootView.getActiveEditor() matches = TagReader.find(editor) return unless matches.length From 35b7ad5ee3979cdffaf84c8603d6051e05c9ca10 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 13:08:58 -0800 Subject: [PATCH 18/30] Add match count to path header text --- src/packages/command-panel/spec/command-panel-spec.coffee | 2 +- src/packages/command-panel/src/preview-list.coffee | 4 +++- themes/Atom - Dark/command-panel.css | 5 +++++ themes/Atom - Light/command-panel.css | 5 +++++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/packages/command-panel/spec/command-panel-spec.coffee b/src/packages/command-panel/spec/command-panel-spec.coffee index 557b21444..635613912 100644 --- a/src/packages/command-panel/spec/command-panel-spec.coffee +++ b/src/packages/command-panel/spec/command-panel-spec.coffee @@ -299,7 +299,7 @@ describe "CommandPanel", -> expect(commandPanel.previewList).toBeVisible() expect(commandPanel.previewList).toMatchSelector ':focus' previewItem = commandPanel.previewList.find("li:contains(sample.js):first") - expect(previewItem.text()).toBe "sample.js" + expect(previewItem.text()).toBe "sample.js(1)" expect(previewItem.next().find('.preview').text()).toBe "var quicksort = function () {" expect(previewItem.next().find('.preview > .match').text()).toBe "quicksort" diff --git a/src/packages/command-panel/src/preview-list.coffee b/src/packages/command-panel/src/preview-list.coffee index 0fd4541e1..34cbd240c 100644 --- a/src/packages/command-panel/src/preview-list.coffee +++ b/src/packages/command-panel/src/preview-list.coffee @@ -34,7 +34,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 path, class: 'path' + @li class: 'path', => + @span path + @span "(#{ops.length})", class: 'path-match-number' for operation in ops {prefix, suffix, match, range} = operation.preview() @li 'data-index': operation.index, class: 'operation', => diff --git a/themes/Atom - Dark/command-panel.css b/themes/Atom - Dark/command-panel.css index 116bb2baf..dfc7f225b 100644 --- a/themes/Atom - Dark/command-panel.css +++ b/themes/Atom - Dark/command-panel.css @@ -60,6 +60,11 @@ display: inline-block; } +.command-panel .preview-list .path-match-number { + padding-left: 8px; + color: rgba(255, 255, 255, .3); +} + .command-panel .preview-list .preview { word-break: break-all; } diff --git a/themes/Atom - Light/command-panel.css b/themes/Atom - Light/command-panel.css index f9e15c3af..4bfff1d22 100644 --- a/themes/Atom - Light/command-panel.css +++ b/themes/Atom - Light/command-panel.css @@ -57,6 +57,11 @@ display: inline-block; } +.command-panel .preview-list .path-match-number { + padding-left: 8px; + color: #3D5075; +} + .command-panel .preview-list .preview { word-break: break-all; } From 9d6853d29edd228c399341979793d8d4f6649fae Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Fri, 25 Jan 2013 16:25:33 -0800 Subject: [PATCH 19/30] By the power of box-flex, tabs --- src/packages/tabs/stylesheets/tabs.css | 18 ++++++++++-------- themes/Atom - Dark/tabs.css | 2 +- themes/Atom - Light/tabs.css | 4 ++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/packages/tabs/stylesheets/tabs.css b/src/packages/tabs/stylesheets/tabs.css index 0239bc734..ebdfad7f2 100644 --- a/src/packages/tabs/stylesheets/tabs.css +++ b/src/packages/tabs/stylesheets/tabs.css @@ -1,14 +1,20 @@ .tabs { -webkit-user-select: none; + display: -webkit-box; + -webkit-box-align: center; } .tab { - display: table-cell; + -webkit-box-flex: 2; position: relative; - width:175px; + width: 175px; + max-width: 175px; min-width: 40px; box-sizing: border-box; - height: 24px; +} + +.tab.active { + -webkit-box-flex: 1; } .tab.file-modified .close-icon { @@ -23,9 +29,5 @@ overflow: hidden; white-space: nowrap; text-overflow: ellipsis; - position: absolute; - left: 9px; - top:4px; - bottom:4px; - right: 21px; + padding: 3px 5px; } \ No newline at end of file diff --git a/themes/Atom - Dark/tabs.css b/themes/Atom - Dark/tabs.css index 732a5c3aa..09942bec6 100644 --- a/themes/Atom - Dark/tabs.css +++ b/themes/Atom - Dark/tabs.css @@ -61,7 +61,7 @@ .tab.active:hover { border-top: 1px solid #4a4a4a; box-shadow: inset -1px 0 0 #595959, inset 1px 0 0 #595959; - border-bottom: 0 none; + border-bottom-color: #424242; background-image: -webkit-linear-gradient(#555555, #424242); } diff --git a/themes/Atom - Light/tabs.css b/themes/Atom - Light/tabs.css index 557b00b39..6b286ad61 100644 --- a/themes/Atom - Light/tabs.css +++ b/themes/Atom - Light/tabs.css @@ -54,7 +54,7 @@ .tab.active, .tab.active:hover { - border-bottom: 0 none; + border-bottom-color: #e5e5e5; box-shadow: inset -1px 0 0 #e0e0e0, inset 1px 0 0 #e0e0e0; background-image: -webkit-linear-gradient(#fefefe, #e7e6e7); } @@ -62,7 +62,7 @@ .tab.active:before, .tab.active:after { position: absolute; - bottom: 0; + bottom: -1px; width: 4px; height: 4px; content: " "; From 22aeda6f1c41efd8d436126519676f32a8aabb4c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 17:31:38 -0800 Subject: [PATCH 20/30] Add move-to-top/bottom support to select list --- spec/app/select-list-spec.coffee | 13 +++++++++++++ src/app/select-list.coffee | 6 ++++++ 2 files changed, 19 insertions(+) diff --git a/spec/app/select-list-spec.coffee b/spec/app/select-list-spec.coffee index e4e4d32cc..88b7990a8 100644 --- a/spec/app/select-list-spec.coffee +++ b/spec/app/select-list-spec.coffee @@ -164,3 +164,16 @@ describe "SelectList", -> miniEditor.trigger 'focusout' expect(selectList.cancelled).toHaveBeenCalled() expect(selectList.detach).toHaveBeenCalled() + + describe "the core:move-to-top event", -> + it "scrolls to the bottom and selects the last element", -> + selectList.trigger 'core:move-down' + expect(list.find('li:eq(1)')).toHaveClass 'selected' + selectList.trigger 'core:move-to-top' + expect(list.find('li:first')).toHaveClass 'selected' + + describe "the core:move-to-bottom event", -> + it "scrolls to the bottom and selects the last element", -> + expect(list.find('li:first')).toHaveClass 'selected' + selectList.trigger 'core:move-to-bottom' + expect(list.find('li:last')).toHaveClass 'selected' diff --git a/src/app/select-list.coffee b/src/app/select-list.coffee index 5bdb3258d..0b4cd9a87 100644 --- a/src/app/select-list.coffee +++ b/src/app/select-list.coffee @@ -26,6 +26,12 @@ class SelectList extends View @miniEditor.on 'focusout', => @cancel() unless @cancelling @on 'core:move-up', => @selectPreviousItem() @on 'core:move-down', => @selectNextItem() + @on 'core:move-to-top', => + @selectItem(@list.find('li:first')) + @list.scrollToTop() + @on 'core:move-to-bottom', => + @selectItem(@list.find('li:last')) + @list.scrollToBottom() @on 'core:confirm', => @confirmSelection() @on 'core:cancel', => @cancel() From 985dd284dcc4714071fd13de0a87da3f96d11273 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 17:37:24 -0800 Subject: [PATCH 21/30] :lipstick: --- spec/app/select-list-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/app/select-list-spec.coffee b/spec/app/select-list-spec.coffee index 88b7990a8..a39c4a128 100644 --- a/spec/app/select-list-spec.coffee +++ b/spec/app/select-list-spec.coffee @@ -166,7 +166,7 @@ describe "SelectList", -> expect(selectList.detach).toHaveBeenCalled() describe "the core:move-to-top event", -> - it "scrolls to the bottom and selects the last element", -> + it "scrolls to the top and selects the first element", -> selectList.trigger 'core:move-down' expect(list.find('li:eq(1)')).toHaveClass 'selected' selectList.trigger 'core:move-to-top' From 1b76b05e4da107c47f24b9375a3abd1a7a2f5776 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 17:51:34 -0800 Subject: [PATCH 22/30] Bind ctrl-C to copy path to clipboard Refs #173 --- spec/app/editor-spec.coffee | 5 +++++ src/app/editor.coffee | 5 +++++ src/app/keymaps/editor.cson | 1 + 3 files changed, 11 insertions(+) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index dd67f2946..f8c6b1cab 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -2212,3 +2212,8 @@ describe "Editor", -> edited = editor.replaceSelectedText(replacer) expect(replaced).toBe true expect(edited).toBe false + + describe "when editor:copy-path is triggered", -> + 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() diff --git a/src/app/editor.coffee b/src/app/editor.coffee index f06487f45..9acca2936 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -182,6 +182,7 @@ class Editor extends View 'editor:close-other-edit-sessions': @destroyInactiveEditSessions 'editor:close-all-edit-sessions': @destroyAllEditSessions 'editor:select-grammar': @selectGrammar + 'editor:copy-path': @copyPathToPasteboard documentation = {} for name, method of editorBindings @@ -1154,3 +1155,7 @@ class Editor extends View @insertText(text, select: true) true + + copyPathToPasteboard: -> + path = @getPath() + pasteboard.write(path) if path? diff --git a/src/app/keymaps/editor.cson b/src/app/keymaps/editor.cson index 2f6da8a83..06f0dd571 100644 --- a/src/app/keymaps/editor.cson +++ b/src/app/keymaps/editor.cson @@ -37,3 +37,4 @@ 'alt-meta-w': 'editor:close-other-edit-sessions' 'meta-P': 'editor:close-all-edit-sessions' 'meta-L': 'editor:select-grammar' + 'ctrl-C': 'editor:copy-path' From 186f461dd7363dea74278a4e2b735b42a9957fbb Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Sat, 26 Jan 2013 11:42:20 -0800 Subject: [PATCH 23/30] Add ctrl-tab shortcut to switch tabs --- src/app/keymaps/atom.cson | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/keymaps/atom.cson b/src/app/keymaps/atom.cson index a4f64a990..97c080d26 100644 --- a/src/app/keymaps/atom.cson +++ b/src/app/keymaps/atom.cson @@ -27,6 +27,7 @@ 'meta-+': 'window:increase-font-size' 'meta--': 'window:decrease-font-size' 'ctrl-w w': 'window:focus-next-pane' + 'ctrl-tab': 'window:focus-next-pane' 'alt-meta-i': 'toggle-dev-tools' From cb4f392fa6dc49b5a124eda1ea02e4babf878e2b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 25 Jan 2013 23:21:46 -0800 Subject: [PATCH 24/30] Set tab index on root-view to 0 Previously if the tree-view was open and was focused and no editors were open and tab was pressed the document body would become focused which would not allow events bound to root view to be triggerable. This ensures that the root-view always gets focus back when another view is tabbed away from. --- src/app/root-view.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/root-view.coffee b/src/app/root-view.coffee index 3a187d6a7..4063ee863 100644 --- a/src/app/root-view.coffee +++ b/src/app/root-view.coffee @@ -18,7 +18,7 @@ class RootView extends View disabledPackages: [] @content: -> - @div id: 'root-view', tabindex: -1, => + @div id: 'root-view', tabindex: 0, => @div id: 'horizontal', outlet: 'horizontal', => @div id: 'vertical', outlet: 'vertical', => @div id: 'panes', outlet: 'panes' From 8fb110505119277284ddd45343002b45051e5183 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Sun, 27 Jan 2013 10:57:48 -0800 Subject: [PATCH 25/30] Detach markdown preview when focus is lost --- .../spec/markdown-preview-spec.coffee | 13 +++++++++++++ .../src/markdown-preview-view.coffee | 8 ++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/packages/markdown-preview/spec/markdown-preview-spec.coffee b/src/packages/markdown-preview/spec/markdown-preview-spec.coffee index 575990c57..4ef0efd5a 100644 --- a/src/packages/markdown-preview/spec/markdown-preview-spec.coffee +++ b/src/packages/markdown-preview/spec/markdown-preview-spec.coffee @@ -57,3 +57,16 @@ describe "MarkdownPreview", -> expect(markdownPreviewView).toExist() markdownPreviewView.trigger('core:cancel') expect(rootView.find('.markdown-preview')).not.toExist() + + describe "when focus is lost", -> + it "removes the markdown preview view", -> + rootView.open('file.md') + editor = rootView.getActiveEditor() + expect(rootView.find('.markdown-preview')).not.toExist() + spyOn(markdownPreview, 'loadHtml') + editor.trigger('markdown-preview:toggle') + + markdownPreviewView = rootView.find('.markdown-preview') + expect(markdownPreviewView).toExist() + markdownPreviewView.blur() + expect(rootView.find('.markdown-preview')).not.toExist() diff --git a/src/packages/markdown-preview/src/markdown-preview-view.coffee b/src/packages/markdown-preview/src/markdown-preview-view.coffee index d7fb9fc6c..914ba8e07 100644 --- a/src/packages/markdown-preview/src/markdown-preview-view.coffee +++ b/src/packages/markdown-preview/src/markdown-preview-view.coffee @@ -14,7 +14,9 @@ class MarkdownPreviewView extends ScrollView initialize: (@rootView) -> super - @command 'core:cancel', => @detach() + + @command 'core:cancel', => @detach() unless @detaching + @on 'focusout', => @detach() unless @detaching toggle: -> if @hasParent() @@ -30,8 +32,10 @@ class MarkdownPreviewView extends ScrollView @focus() detach: -> - super() + @detaching = true + super @rootView.focus() + @detaching = false getActivePath: -> @rootView.getActiveEditor()?.getPath() From 162e3494b267adc156b493c556eb1b5a7d7e9cf9 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sun, 27 Jan 2013 13:09:27 -0700 Subject: [PATCH 26/30] Tolerate undefined `rootView` global when loading a package This eliminates warnings when we activate packages in specs without setting up the `rootView`. --- src/app/atom-package.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/atom-package.coffee b/src/app/atom-package.coffee index 8fc6b4908..bb1ce071b 100644 --- a/src/app/atom-package.coffee +++ b/src/app/atom-package.coffee @@ -16,7 +16,7 @@ class AtomPackage extends Package @loadMetadata() @loadKeymaps() @loadStylesheets() if @autoloadStylesheets - rootView.activatePackage(@name, this) unless @isDirectory + rootView?.activatePackage(@name, this) unless @isDirectory catch e console.warn "Failed to load package named '#{@name}'", e.stack this From c16acc6b2c20d807d7205509c0901a7d8c534562 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sun, 27 Jan 2013 12:12:39 -0700 Subject: [PATCH 27/30] Disable 'package-that-throws-an-exception' except in spec that uses it Loading this package logs a warning, so to minimize noise in the spec console, it should only be loaded when `console.warn` is mocked. --- spec/app/atom-spec.coffee | 1 + spec/spec-helper.coffee | 1 + 2 files changed, 2 insertions(+) diff --git a/spec/app/atom-spec.coffee b/spec/app/atom-spec.coffee index f09390343..fdf7c2e1e 100644 --- a/spec/app/atom-spec.coffee +++ b/spec/app/atom-spec.coffee @@ -19,6 +19,7 @@ describe "the `atom` global", -> expect(rootView.activatePackage).toHaveBeenCalled() it "logs warning instead of throwing an exception if a package fails to load", -> + config.set("core.disabledPackages", []) spyOn(console, "warn") expect(-> atom.loadPackage("package-that-throws-an-exception")).not.toThrow() expect(console.warn).toHaveBeenCalled() diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 01736d4af..a0e49740a 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -35,6 +35,7 @@ beforeEach -> spyOn(config, 'save') config.set "editor.fontSize", 16 config.set "editor.autoIndent", false + config.set "core.disabledPackages", ["package-that-throws-an-exception"] # make editor display updates synchronous spyOn(Editor.prototype, 'requestDisplayUpdate').andCallFake -> @updateDisplay() From ecc50506c7ee4d3e97cec688635e87788d8cfcfa Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Sun, 27 Jan 2013 12:54:23 -0800 Subject: [PATCH 28/30] Render trailing carriage return as an invisible --- spec/app/editor-spec.coffee | 14 ++++++++++++++ src/app/editor.coffee | 5 +++-- src/app/token.coffee | 3 +++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index f8c6b1cab..f5a86ccbf 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -1604,6 +1604,20 @@ describe "Editor", -> expect(rightEditor.find(".line:first").text()).toBe "_tab _;" expect(leftEditor.find(".line:first").text()).toBe "_tab _;" + it "displays trailing carriage return using a visible non-empty value", -> + editor.setText "a line that ends with a carriage return\r\n" + editor.attachToDom() + + expect(config.get("editor.showInvisibles")).toBeFalsy() + expect(editor.renderedLines.find('.line:first').text()).toBe "a line that ends with a carriage return\n" + + config.set("editor.showInvisibles", true) + cr = editor.invisibles?.cr + expect(cr).toBeTruthy() + eol = editor.invisibles?.eol + expect(eol).toBeTruthy() + expect(editor.renderedLines.find('.line:first').text()).toBe "a line that ends with a carriage return#{cr}#{eol}" + describe "gutter rendering", -> beforeEach -> editor.attachToDom(heightInLines: 5.5) diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 9acca2936..bd4f93934 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -311,9 +311,10 @@ class Editor extends View setInvisibles: (@invisibles={}) -> _.defaults @invisibles, - eol: '\u00ac', - space: '\u2022', + eol: '\u00ac' + space: '\u2022' tab: '\u00bb' + cr: '\u00a4' @resetDisplay() checkoutHead: -> @getBuffer().checkoutHead() diff --git a/src/app/token.coffee b/src/app/token.coffee index e141dd7bf..0c595c908 100644 --- a/src/app/token.coffee +++ b/src/app/token.coffee @@ -80,5 +80,8 @@ class Token if hasTrailingWhitespace html = html.replace /[ ]+$/, (match) -> "" + if invisibles.cr + html = html.replace /\r$/, (match) -> + "" html From 98614592af81712bd0626682811ecbf04b2d88c8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki & Nathan Sobo Date: Sun, 27 Jan 2013 15:45:53 -0800 Subject: [PATCH 29/30] Store line endings on a per-line basis in Buffer The line ending for each line is recorded and reused when lines are modified or inserted. Closes #166 --- spec/app/buffer-spec.coffee | 48 ++++++++++++++++++++++++++ spec/app/editor-spec.coffee | 2 +- spec/app/language-mode-spec.coffee | 6 ++-- src/app/buffer-change-operation.coffee | 44 ++++++++++++++++------- src/app/buffer.coffee | 26 ++++++++------ src/app/editor.coffee | 7 ++-- src/app/screen-line.coffee | 2 +- src/app/token.coffee | 3 -- src/app/tokenized-buffer.coffee | 3 +- 9 files changed, 108 insertions(+), 33 deletions(-) diff --git a/spec/app/buffer-spec.coffee b/spec/app/buffer-spec.coffee index a93bae30a..ea10907cf 100644 --- a/spec/app/buffer-spec.coffee +++ b/spec/app/buffer-spec.coffee @@ -833,3 +833,51 @@ describe 'Buffer', -> expect(buffer.getText()).toBe "a" buffer.append("b\nc"); expect(buffer.getText()).toBe "ab\nc" + + describe "line ending support", -> + describe ".lineEndingForRow(line)", -> + it "return the line ending for each buffer line", -> + buffer.setText("a\r\nb\nc") + expect(buffer.lineEndingForRow(0)).toBe '\r\n' + expect(buffer.lineEndingForRow(1)).toBe '\n' + expect(buffer.lineEndingForRow(2)).toBeUndefined() + + describe ".lineForRow(line)", -> + it "returns the line text without the line ending for both lf and crlf lines", -> + buffer.setText("a\r\nb\nc") + expect(buffer.lineForRow(0)).toBe 'a' + expect(buffer.lineForRow(1)).toBe 'b' + expect(buffer.lineForRow(2)).toBe 'c' + + describe ".getText()", -> + it "returns the text with the corrent line endings for each row", -> + buffer.setText("a\r\nb\nc") + expect(buffer.getText()).toBe "a\r\nb\nc" + buffer.setText("a\r\nb\nc\n") + expect(buffer.getText()).toBe "a\r\nb\nc\n" + + describe "when editing a line", -> + it "preserves the existing line ending", -> + buffer.setText("a\r\nb\nc") + buffer.insert([0, 1], "1") + expect(buffer.getText()).toBe "a1\r\nb\nc" + + describe "when inserting text with multiple lines", -> + describe "when the current line has a line ending", -> + it "uses the same line ending as the line where the text is inserted", -> + buffer.setText("a\r\n") + buffer.insert([0,1], "hello\n1\n\n2") + expect(buffer.getText()).toBe "ahello\r\n1\r\n\r\n2\r\n" + + describe "when the current line has no line ending (because it's the last line of the buffer)", -> + describe "when the buffer contains only a single line", -> + it "honors the line endings in the inserted text", -> + buffer.setText("initialtext") + buffer.append("hello\n1\r\n2\n") + expect(buffer.getText()).toBe "initialtexthello\n1\r\n2\n" + + describe "when the buffer contains a preceding line", -> + it "uses the line ending of the preceding line", -> + buffer.setText("\ninitialtext") + buffer.append("hello\n1\r\n2\n") + expect(buffer.getText()).toBe "\ninitialtexthello\n1\n2\n" diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index f5a86ccbf..445f2faf1 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -1609,7 +1609,7 @@ describe "Editor", -> editor.attachToDom() expect(config.get("editor.showInvisibles")).toBeFalsy() - expect(editor.renderedLines.find('.line:first').text()).toBe "a line that ends with a carriage return\n" + expect(editor.renderedLines.find('.line:first').text()).toBe "a line that ends with a carriage return" config.set("editor.showInvisibles", true) cr = editor.invisibles?.cr diff --git a/spec/app/language-mode-spec.coffee b/spec/app/language-mode-spec.coffee index 9e1cd8b71..775baefa1 100644 --- a/spec/app/language-mode-spec.coffee +++ b/spec/app/language-mode-spec.coffee @@ -308,16 +308,16 @@ describe "LanguageMode", -> expect(buffer.lineForRow(3)).toBe " font-weight: bold !important;" it "uncomments lines with leading whitespace", -> - buffer.replaceLines(2, 2, " /*width: 110%;*/") + buffer.change([[2, 0], [2, Infinity]], " /*width: 110%;*/") languageMode.toggleLineCommentsForBufferRows(2, 2) expect(buffer.lineForRow(2)).toBe " width: 110%;" it "uncomments lines with trailing whitespace", -> - buffer.replaceLines(2, 2, "/*width: 110%;*/ ") + buffer.change([[2, 0], [2, Infinity]], "/*width: 110%;*/ ") languageMode.toggleLineCommentsForBufferRows(2, 2) expect(buffer.lineForRow(2)).toBe "width: 110%; " it "uncomments lines with leading and trailing whitespace", -> - buffer.replaceLines(2, 2, " /*width: 110%;*/ ") + buffer.change([[2, 0], [2, Infinity]], " /*width: 110%;*/ ") languageMode.toggleLineCommentsForBufferRows(2, 2) expect(buffer.lineForRow(2)).toBe " width: 110%; " diff --git a/src/app/buffer-change-operation.coffee b/src/app/buffer-change-operation.coffee index 6fd0f2654..c50bb2308 100644 --- a/src/app/buffer-change-operation.coffee +++ b/src/app/buffer-change-operation.coffee @@ -1,4 +1,5 @@ Range = require 'range' +_ = require 'underscore' module.exports = class BufferChangeOperation @@ -26,18 +27,37 @@ class BufferChangeOperation oldText: @newText newText: @oldText + splitLines: (text) -> + lines = text.split('\n') + lineEndings = [] + for line, index in lines + if _.endsWith(line, '\r') + lines[index] = line[0..-2] + lineEndings[index] = '\r\n' + else + lineEndings[index] = '\n' + {lines, lineEndings} + changeBuffer: ({ oldRange, newRange, newText, oldText }) -> { prefix, suffix } = @buffer.prefixAndSuffixForRange(oldRange) - newTextLines = newText.split('\n') - if newTextLines.length == 1 - newTextLines = [prefix + newText + suffix] - else - lastLineIndex = newTextLines.length - 1 - newTextLines[0] = prefix + newTextLines[0] - newTextLines[lastLineIndex] += suffix + {lines, lineEndings} = @splitLines(newText) + lastLineIndex = lines.length - 1 - @buffer.replaceLines(oldRange.start.row, oldRange.end.row, newTextLines) + if lines.length == 1 + lines = [prefix + newText + suffix] + else + lines[0] = prefix + lines[0] + lines[lastLineIndex] += suffix + + startRow = oldRange.start.row + endRow = oldRange.end.row + if suggestedLineEnding = @buffer.suggestedLineEndingForRow(startRow) + lineEndings[index] = suggestedLineEnding for index in [0..lastLineIndex] + @buffer.lines[startRow..endRow] = lines + @buffer.lineEndings[startRow..endRow] = lineEndings + @buffer.cachedMemoryContents = null + @buffer.conflict = false if @buffer.conflict and !@buffer.isModified() event = { oldRange, newRange, oldText, newText } @buffer.trigger 'changed', event @@ -47,11 +67,11 @@ class BufferChangeOperation calculateNewRange: (oldRange, newText) -> newRange = new Range(oldRange.start.copy(), oldRange.start.copy()) - newTextLines = newText.split('\n') - if newTextLines.length == 1 + {lines} = @splitLines(newText) + if lines.length == 1 newRange.end.column += newText.length else - lastLineIndex = newTextLines.length - 1 + lastLineIndex = lines.length - 1 newRange.end.row += lastLineIndex - newRange.end.column = newTextLines[lastLineIndex].length + newRange.end.column = lines[lastLineIndex].length newRange diff --git a/src/app/buffer.coffee b/src/app/buffer.coffee index 9b205b7e0..cbff0b2d9 100644 --- a/src/app/buffer.coffee +++ b/src/app/buffer.coffee @@ -19,6 +19,7 @@ class Buffer cachedMemoryContents: null conflict: false lines: null + lineEndings: null file: null anchors: null anchorRanges: null @@ -29,6 +30,7 @@ class Buffer @anchors = [] @anchorRanges = [] @lines = [''] + @lineEndings = [] if path throw "Path '#{path}' does not exist" unless fs.exists(path) @@ -104,9 +106,10 @@ class Buffer null getText: -> - @cachedMemoryContents ?= @lines.join('\n') + @cachedMemoryContents ?= @getTextInRange(@getRange()) setText: (text) -> + @lineEndings = [] @change(@getRange(), text) getRange: -> @@ -118,12 +121,14 @@ class Buffer return @lines[range.start.row][range.start.column...range.end.column] multipleLines = [] - multipleLines.push @lines[range.start.row][range.start.column..] # first line + multipleLines.push @lineForRow(range.start.row)[range.start.column..] # first line + multipleLines.push @lineEndingForRow(range.start.row) for row in [range.start.row + 1...range.end.row] - multipleLines.push @lines[row] # middle lines - multipleLines.push @lines[range.end.row][0...range.end.column] # last line + multipleLines.push @lineForRow(row) # middle lines + multipleLines.push @lineEndingForRow(row) + multipleLines.push @lineForRow(range.end.row)[0...range.end.column] # last line - return multipleLines.join '\n' + return multipleLines.join '' getLines: -> @lines @@ -131,6 +136,12 @@ class Buffer lineForRow: (row) -> @lines[row] + lineEndingForRow: (row) -> + @lineEndings[row] unless row is @getLastRow() + + suggestedLineEndingForRow: (row) -> + @lineEndingForRow(row) ? @lineEndingForRow(row - 1) + lineLengthForRow: (row) -> @lines[row].length @@ -214,11 +225,6 @@ class Buffer prefix: @lines[range.start.row][0...range.start.column] suffix: @lines[range.end.row][range.end.column..] - replaceLines: (startRow, endRow, newLines) -> - @lines[startRow..endRow] = newLines - @cachedMemoryContents = null - @conflict = false if @conflict and !@isModified() - pushOperation: (operation, editSession) -> if @undoManager @undoManager.pushOperation(operation, editSession) diff --git a/src/app/editor.coffee b/src/app/editor.coffee index bd4f93934..b986c1e6a 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -1076,8 +1076,11 @@ class Editor extends View position += token.value.length popScope() while scopeStack.length > 0 - if not @mini and invisibles?.eol - line.push("") + if invisibles and not @mini + if invisibles.cr and screenLine.lineEnding is '\r\n' + line.push("") + if invisibles.eol + line.push("") line.push('') line.join('') diff --git a/src/app/screen-line.coffee b/src/app/screen-line.coffee index 31d93e879..2d01a07b1 100644 --- a/src/app/screen-line.coffee +++ b/src/app/screen-line.coffee @@ -2,7 +2,7 @@ _ = require 'underscore' module.exports = class ScreenLine - constructor: ({tokens, @ruleStack, @bufferRows, @startBufferColumn, @fold, tabLength}) -> + constructor: ({tokens, @lineEnding, @ruleStack, @bufferRows, @startBufferColumn, @fold, tabLength}) -> @tokens = @breakOutAtomicTokens(tokens, tabLength) @bufferRows ?= 1 @startBufferColumn ?= 0 diff --git a/src/app/token.coffee b/src/app/token.coffee index 0c595c908..e141dd7bf 100644 --- a/src/app/token.coffee +++ b/src/app/token.coffee @@ -80,8 +80,5 @@ class Token if hasTrailingWhitespace html = html.replace /[ ]+$/, (match) -> "" - if invisibles.cr - html = html.replace /\r$/, (match) -> - "" html diff --git a/src/app/tokenized-buffer.coffee b/src/app/tokenized-buffer.coffee index 6646fd54f..9e0930bf0 100644 --- a/src/app/tokenized-buffer.coffee +++ b/src/app/tokenized-buffer.coffee @@ -137,8 +137,9 @@ class TokenizedBuffer buildTokenizedScreenLineForRow: (row, ruleStack) -> line = @buffer.lineForRow(row) + lineEnding = @buffer.lineEndingForRow(row) { tokens, ruleStack } = @languageMode.tokenizeLine(line, ruleStack, row is 0) - new ScreenLine({tokens, ruleStack, @tabLength}) + new ScreenLine({tokens, ruleStack, @tabLength, lineEnding}) lineForScreenRow: (row) -> @linesForScreenRows(row, row)[0] From f6fe2bdc97c9edc2ca947d3b212ca74babb2481d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki & Nathan Sobo Date: Sun, 27 Jan 2013 15:58:00 -0800 Subject: [PATCH 30/30] Don't normalize line endings from Buffer.setText BufferChangeOperation now takes an options hash that can specify whether line endings should be normalized. This option is set to false when Buffer.setText is called. This replaces the previous assignment of lineEndings to [] with a more explicit mechanism. --- src/app/buffer-change-operation.coffee | 7 +++++-- src/app/buffer.coffee | 7 +++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/app/buffer-change-operation.coffee b/src/app/buffer-change-operation.coffee index c50bb2308..2a31ab244 100644 --- a/src/app/buffer-change-operation.coffee +++ b/src/app/buffer-change-operation.coffee @@ -9,7 +9,8 @@ class BufferChangeOperation newRange: null newText: null - constructor: ({@buffer, @oldRange, @newText}) -> + constructor: ({@buffer, @oldRange, @newText, @options}) -> + @options ?= {} do: -> @oldText = @buffer.getTextInRange(@oldRange) @@ -52,7 +53,9 @@ class BufferChangeOperation startRow = oldRange.start.row endRow = oldRange.end.row - if suggestedLineEnding = @buffer.suggestedLineEndingForRow(startRow) + + normalizeLineEndings = @options.normalizeLineEndings ? true + if normalizeLineEndings and suggestedLineEnding = @buffer.suggestedLineEndingForRow(startRow) lineEndings[index] = suggestedLineEnding for index in [0..lastLineIndex] @buffer.lines[startRow..endRow] = lines @buffer.lineEndings[startRow..endRow] = lineEndings diff --git a/src/app/buffer.coffee b/src/app/buffer.coffee index cbff0b2d9..266b30ba2 100644 --- a/src/app/buffer.coffee +++ b/src/app/buffer.coffee @@ -109,8 +109,7 @@ class Buffer @cachedMemoryContents ?= @getTextInRange(@getRange()) setText: (text) -> - @lineEndings = [] - @change(@getRange(), text) + @change(@getRange(), text, normalizeLineEndings: false) getRange: -> new Range([0, 0], [@getLastRow(), @getLastLine().length]) @@ -206,9 +205,9 @@ class Buffer delete: (range) -> @change(range, '') - change: (oldRange, newText) -> + change: (oldRange, newText, options) -> oldRange = Range.fromObject(oldRange) - operation = new BufferChangeOperation({buffer: this, oldRange, newText}) + operation = new BufferChangeOperation({buffer: this, oldRange, newText, options}) range = @pushOperation(operation) range