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 dd67f2946..445f2faf1 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" + + 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) @@ -2212,3 +2226,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/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/spec/app/select-list-spec.coffee b/spec/app/select-list-spec.coffee index 01ffeb445..a39c4a128 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' @@ -153,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 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' + 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/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 diff --git a/src/app/buffer-change-operation.coffee b/src/app/buffer-change-operation.coffee index 6fd0f2654..2a31ab244 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 @@ -8,7 +9,8 @@ class BufferChangeOperation newRange: null newText: null - constructor: ({@buffer, @oldRange, @newText}) -> + constructor: ({@buffer, @oldRange, @newText, @options}) -> + @options ?= {} do: -> @oldText = @buffer.getTextInRange(@oldRange) @@ -26,18 +28,39 @@ 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 + + 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 + @buffer.cachedMemoryContents = null + @buffer.conflict = false if @buffer.conflict and !@buffer.isModified() event = { oldRange, newRange, oldText, newText } @buffer.trigger 'changed', event @@ -47,11 +70,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..266b30ba2 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,10 +106,10 @@ class Buffer null getText: -> - @cachedMemoryContents ?= @lines.join('\n') + @cachedMemoryContents ?= @getTextInRange(@getRange()) setText: (text) -> - @change(@getRange(), text) + @change(@getRange(), text, normalizeLineEndings: false) getRange: -> new Range([0, 0], [@getLastRow(), @getLastLine().length]) @@ -118,12 +120,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 +135,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 @@ -195,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 @@ -214,11 +224,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/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/app/editor.coffee b/src/app/editor.coffee index a40f02a18..ce86c005f 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 @@ -310,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() @@ -1079,8 +1081,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('') @@ -1159,3 +1164,7 @@ class Editor extends View @insertText(text, select: true) true + + copyPathToPasteboard: -> + path = @getPath() + pasteboard.write(path) if path? 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' diff --git a/src/app/keymaps/editor.cson b/src/app/keymaps/editor.cson index 2f48d27bb..06f0dd571 100644 --- a/src/app/keymaps/editor.cson +++ b/src/app/keymaps/editor.cson @@ -36,4 +36,5 @@ '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' + 'ctrl-C': 'editor:copy-path' 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' 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/select-list.coffee b/src/app/select-list.coffee index 020aaf734..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() @@ -62,6 +68,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) 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] diff --git a/src/packages/command-panel/spec/command-panel-spec.coffee b/src/packages/command-panel/spec/command-panel-spec.coffee index f4dc193ef..635613912 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", -> @@ -297,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" @@ -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() @@ -405,28 +411,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/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 44280eac5..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', => @@ -56,16 +58,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) @@ -90,6 +86,9 @@ class PreviewList extends ScrollView @rootView.focus() false + getPathCount: -> + _.keys(_.groupBy(@operations, (operation) -> operation.getPath())).length + getOperations: -> new Array(@operations...) diff --git a/src/packages/gists/index.coffee b/src/packages/gists/index.coffee new file mode 100644 index 000000000..6205cb366 --- /dev/null +++ b/src/packages/gists/index.coffee @@ -0,0 +1,12 @@ +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/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..434603636 --- /dev/null +++ b/src/packages/gists/lib/gists.coffee @@ -0,0 +1,31 @@ +$ = require 'jquery' +{$$} = require 'space-pen' + +module.exports = +class Gists + + @activate: (rootView) -> new Gists(rootView) + + constructor: (@rootView) -> + + 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) + notification = $$ -> + @div class: 'gist-notification', => + @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 new file mode 100644 index 000000000..64227744a --- /dev/null +++ b/src/packages/gists/spec/gists-spec.coffee @@ -0,0 +1,61 @@ +RootView = require 'root-view' +$ = require 'jquery' + +describe "Gists package", -> + + [rootView, editor] = [] + + beforeEach -> + rootView = new RootView(fixturesProject.resolve('sample.js')) + atom.loadPackage('gists').getInstance() + editor = rootView.getActiveEditor() + spyOn($, 'ajax') + + afterEach -> + rootView.deactivate() + + describe "when gist:create is triggered on an editor", -> + + describe "when the editor has no selection", -> + [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() + + 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 .message').text()).toBe 'Gist 1 created' + advanceClock(2000) + expect(rootView.find('.gist-notification')).not.toExist() + + 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() diff --git a/src/packages/go-to-line/index.coffee b/src/packages/go-to-line/index.coffee new file mode 100644 index 000000000..12601c00e --- /dev/null +++ b/src/packages/go-to-line/index.coffee @@ -0,0 +1,12 @@ +DeferredAtomPackage = require 'deferred-atom-package' + +module.exports = +class GoToLinePackage extends DeferredAtomPackage + + loadEvents: + 'editor:go-to-line': '.editor' + + instanceClass: 'go-to-line/lib/go-to-line-view' + + onLoadEvent: (event, instance) -> + instance.toggle(event.currentTargetView()) diff --git a/src/packages/go-to-line/keymaps/go-to-line.cson b/src/packages/go-to-line/keymaps/go-to-line.cson new file mode 100644 index 000000000..5686829bd --- /dev/null +++ b/src/packages/go-to-line/keymaps/go-to-line.cson @@ -0,0 +1,6 @@ +'body': + '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/go-to-line/lib/go-to-line-view.coffee b/src/packages/go-to-line/lib/go-to-line-view.coffee new file mode 100644 index 000000000..ce99ece31 --- /dev/null +++ b/src/packages/go-to-line/lib/go-to-line-view.coffee @@ -0,0 +1,54 @@ +{View} = require 'space-pen' +Editor = require 'editor' +$ = require 'jquery' +Point = require 'point' + +module.exports = +class GoToLineView extends View + + @activate: (rootView) -> new GoToLineView(rootView) + + @content: -> + @div class: 'go-to-line', => + @subview 'miniEditor', new Editor(mini: true) + @div class: 'message', outlet: 'message' + + initialize: (@rootView) -> + @miniEditor.on 'focusout', => @detach() + @on 'core:confirm', => @confirm() + @on 'core:cancel', => @detach() + + @miniEditor.preempt 'textInput', (e) => + false unless e.originalEvent.data.match(/[0-9]/) + + toggle: -> + if @hasParent() + @detach() + else + @attach() + + detach: -> + return unless @hasParent() + + @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-#{@rootView.getActiveEditor().getLineCount()}") + @miniEditor.focus() 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/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() 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 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/command-panel.css b/themes/Atom - Dark/command-panel.css index 8f4a6e405..dfc7f225b 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); } @@ -53,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 - 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/themes/Atom - Dark/go-to-line.css b/themes/Atom - Dark/go-to-line.css new file mode 100644 index 000000000..4ceec81aa --- /dev/null +++ b/themes/Atom - Dark/go-to-line.css @@ -0,0 +1,27 @@ +.go-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; +} + +.go-to-line .editor { + box-sizing: border-box; + padding: 5px; +} + +.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 4d5c95b40..28f90e051 100644 --- a/themes/Atom - Dark/package.json +++ b/themes/Atom - Dark/package.json @@ -14,6 +14,8 @@ "command-panel.css", "command-palette.css", "command-logger.css", - "autocomplete.css" + "autocomplete.css", + "gists.css", + "go-to-line.css" ] } 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/command-panel.css b/themes/Atom - Light/command-panel.css index 5344b859d..4bfff1d22 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); } @@ -50,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; } diff --git a/themes/Atom - Light/gists.css b/themes/Atom - Light/gists.css new file mode 100644 index 000000000..0209ce3e3 --- /dev/null +++ b/themes/Atom - Light/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: #444; +} + +.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/themes/Atom - Light/go-to-line.css b/themes/Atom - Light/go-to-line.css new file mode 100644 index 000000000..9f6c3ec8b --- /dev/null +++ b/themes/Atom - Light/go-to-line.css @@ -0,0 +1,27 @@ +.go-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; +} + +.go-to-line .editor { + box-sizing: border-box; + padding: 5px; +} + +.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 4d5c95b40..28f90e051 100644 --- a/themes/Atom - Light/package.json +++ b/themes/Atom - Light/package.json @@ -14,6 +14,8 @@ "command-panel.css", "command-palette.css", "command-logger.css", - "autocomplete.css" + "autocomplete.css", + "gists.css", + "go-to-line.css" ] } 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: " ";