Merge branch 'master' into config

This commit is contained in:
Nathan Sobo
2012-12-28 11:32:24 -06:00
18 changed files with 281 additions and 69 deletions

View File

@@ -63,3 +63,7 @@ class Git
checkoutHead: (path) ->
@repo.checkoutHead(@relativize(path))
getDiffStats: (path) ->
stats = @repo.getDiffStats(@relativize(path))
stats or {'added': 0, 'deleted': 0}

View File

@@ -52,20 +52,24 @@ class RootView extends View
panesViewState: @panes.children().view()?.serialize()
packageStates: @serializePackages()
handleEvents: ->
@on 'toggle-dev-tools', => atom.toggleDevTools()
@on 'focus', (e) =>
if @getActiveEditor()
@getActiveEditor().focus()
handleFocus: (e) ->
if @getActiveEditor()
@getActiveEditor().focus()
false
else
@setTitle(null)
focusableChild = this.find("[tabindex=-1]:visible:first")
if focusableChild.length
focusableChild.focus()
false
else
@setTitle(null)
focusableChild = this.find("[tabindex=-1]:visible:first")
if focusableChild.length
focusableChild.focus()
false
else
true
true
handleEvents: ->
@on 'toggle-dev-tools', => atom.toggleDevTools()
@on 'focus', (e) => @handleFocus(e)
$(window).on 'focus', (e) =>
@handleFocus(e) if document.activeElement is document.body
@on 'active-editor-path-change', (e, path) =>
@project.setPath(path) unless @project.getRootDirectory()

View File

@@ -166,3 +166,12 @@ describe "StatusBar", ->
fs.write(path, originalPathText)
$(window).trigger 'focus'
expect(statusBar.gitStatusIcon).not.toHaveClass('modified-status-icon')
it "displays the diff stat for modified files", ->
fs.write(path, "i've changed for the worse")
rootView.open(path)
expect(statusBar.gitStatusIcon).toHaveText('+1,-1')
it "displays the diff stat for new files", ->
rootView.open(newPath)
expect(statusBar.gitStatusIcon).toHaveText('+1')

View File

@@ -79,8 +79,18 @@ class StatusBar extends View
@gitStatusIcon.removeClass().addClass('git-status octicons')
if @buffer.getGit()?.isPathModified(path)
@gitStatusIcon.addClass('modified-status-icon')
else if @buffer.getGit()?.isPathNew(path)
stats = @buffer.getGit().getDiffStats(path)
if stats.added and stats.deleted
@gitStatusIcon.text("+#{stats.added},-#{stats.deleted}")
else if stats.added
@gitStatusIcon.text("+#{stats.added}")
else if stats.deleted
@gitStatusIcon.text("-#{stats.deleted}")
else
@gitStatusIcon.text('')
else if @buffer.getGit()?.isPathNew(path)
@gitStatusIcon.addClass('new-status-icon')
@gitStatusIcon.text("+#{@buffer.getLineCount()}")
updatePathText: ->
if path = @editor.getPath()

View File

@@ -11,6 +11,25 @@ class Tab extends View
@updateFileName()
@editSession.on 'buffer-path-change.tab', =>
@updateFileName()
@subscribeToBuffer()
updateTab: ->
@updateBufferHasModifiedText(@buffer.isModified())
subscribeToBuffer: ->
@buffer = @editSession.buffer
@subscribe @buffer, 'contents-modified.tabs', (e) => @updateBufferHasModifiedText(e.differsFromDisk)
@subscribe @buffer, 'after-save.tabs', => @updateTab()
@subscribe @buffer, 'git-status-change.tabs', => @updateTab()
@updateTab()
updateBufferHasModifiedText: (differsFromDisk) ->
if differsFromDisk
@toggleClass('file-modified') unless @isModified
@isModified = true
else
@removeClass('file-modified') if @isModified
@isModified = false
updateFileName: ->
@fileName.text(@editSession.buffer.getBaseName() ? 'untitled')

View File

@@ -1,14 +1,13 @@
.tabs {
background: #333333;
border-bottom: 4px solid #424242;
font: caption !important;
font: caption;
}
.tab {
cursor: default;
padding: 2px 21px 2px 9px;
background-image: -webkit-linear-gradient(#444, #3d3d3d);
color: #a5aaaa;
display: table-cell;
position: relative;
width:175px;
@@ -21,6 +20,43 @@
height: 24px;
}
.tab,
.tab .close-icon {
color: #aaa;
}
.tab.file-modified .close-icon {
border-color: #aaa;
}
.tab.active,
.tab.active:hover,
.tab.active .close-icon {
color: #e6e6e6;
}
.tab.file-modified.active .close-icon {
border-color: #e6e6e6;
}
.tab:hover .close-icon {
color: #c8c8c8;
border-color: #c8c8c8;
}
.tab.file-modified .close-icon {
border: 3px solid #777;
top: 6px;
border-radius: 10px;
width: 5px;
height: 5px;
right: 5px;
}
.tab.file-modified .close-icon:before {
content: "";
}
.tab:first-child {
box-shadow: inset 0 0 5px #383838, 0 1px 0 #585858, inset -1px 0 0 #4a4a4a;
}
@@ -32,7 +68,6 @@
.tab.active,
.tab.active:hover {
color: #dae6e6;
border-top: 1px solid #4a4a4a;
box-shadow: inset -1px 0 0 #595959, inset 1px 0 0 #595959;
border-bottom: 0 none;
@@ -66,12 +101,12 @@
}
.tab:hover {
color: #c8c8c5;
color: #c8c8c8;
background-image: -webkit-linear-gradient(#474747, #444444);
}
.tab .file-name {
font-size: 11px !important;
font-size: 11px;
display: block;
overflow: hidden;
white-space: nowrap;
@@ -90,7 +125,6 @@
width: 14px;
height: 14px;
display: block;
color: #777;
cursor: pointer;
position: absolute;
right: 4px;

View File

@@ -194,6 +194,19 @@ describe "TreeView", ->
expect(treeView).not.toMatchSelector(':focus')
expect(rootView.getActiveEditor().isFocused).toBeTruthy()
describe "when core:close is triggered on the tree view", ->
it "detaches the TreeView, focuses the RootView and does not bubble the core:close event", ->
treeView.attach()
treeView.focus()
rootViewCloseHandler = jasmine.createSpy('rootViewCloseHandler')
rootView.on 'core:close', rootViewCloseHandler
spyOn(rootView, 'focus')
treeView.trigger('core:close')
expect(rootView.focus).toHaveBeenCalled()
expect(rootViewCloseHandler).not.toHaveBeenCalled()
expect(treeView.hasParent()).toBeFalsy()
describe "when a directory's disclosure arrow is clicked", ->
it "expands / collapses the associated directory", ->
subdir = treeView.root.find('.entries > li:contains(dir1)').view()
@@ -859,3 +872,31 @@ describe "TreeView", ->
config.set("core.hideGitIgnoredFiles", false)
expect(treeView.find('.file:contains(tree-view.js)').length).toBe 1
describe "Git status decorations", ->
[ignoreFile, modifiedFile, originalFileContent] = []
beforeEach ->
config.set "core.hideGitIgnoredFiles", false
ignoreFile = fs.join(require.resolve('fixtures/tree-view'), '.gitignore')
fs.write(ignoreFile, 'tree-view.js')
modifiedFile = fs.join(require.resolve('fixtures/tree-view'), 'tree-view.txt')
originalFileContent = fs.read(modifiedFile)
fs.write modifiedFile, 'ch ch changes'
treeView.updateRoot()
afterEach ->
fs.remove(ignoreFile) if fs.exists(ignoreFile)
fs.write modifiedFile, originalFileContent
describe "when a file is modified", ->
it "adds a custom style", ->
expect(treeView.find('.file:contains(tree-view.txt)')).toHaveClass 'modified'
describe "when a file is new", ->
it "adds a custom style", ->
expect(treeView.find('.file:contains(.gitignore)')).toHaveClass 'new'
describe "when a file is ignored", ->
it "adds a custom style", ->
expect(treeView.find('.file:contains(tree-view.js)')).toHaveClass 'ignored'

View File

@@ -25,7 +25,13 @@ class FileView extends View
else
@fileName.addClass('text-name')
@addClass('ignored') if new Git(path).isPathIgnored(path)
git = new Git(path)
if git.isPathIgnored(path)
@addClass('ignored')
else if git.isPathModified(path)
@addClass('modified')
else if git.isPathNew(path)
@addClass('new')
getPath: ->
@file.path

View File

@@ -48,7 +48,7 @@ class TreeView extends ScrollView
@on 'click', '.entry', (e) => @entryClicked(e)
@command 'core:move-up', => @moveUp()
@command 'core:move-down', => @moveDown()
@command 'core:close', => false
@command 'core:close', => @detach(); false
@command 'tree-view:expand-directory', => @expandDirectory()
@command 'tree-view:collapse-directory', => @collapseDirectory()
@command 'tree-view:open-selected-entry', => @openSelectedEntry(true)

View File

@@ -38,39 +38,23 @@ describe "WrapGuide", ->
expect(wrapGuide.position().left).toBeGreaterThan(initial)
expect(wrapGuide).toBeVisible()
describe "overriding getGuideColumn", ->
it "invokes the callback with the editor path", ->
editorPath = null
wrapGuide.getGuideColumn = (path) ->
editorPath = path
80
describe "using a custom config column", ->
it "places the wrap guide at the custom column", ->
config.set('wrapGuide.columns', [{pattern: '\.js$', column: 20}])
wrapGuide.updateGuide()
expect(editorPath).toBe(require.resolve('fixtures/sample.js'))
it "invokes the callback with a default value", ->
column = null
wrapGuide.getGuideColumn = (path, defaultColumn) ->
editorPath = path
column = defaultColumn
defaultColumn
width = editor.charWidth * 20
expect(width).toBeGreaterThan(0)
expect(wrapGuide.position().left).toBe(width)
it "uses the default column when no custom column matches the path", ->
config.set('wrapGuide.columns', [{pattern: '\.jsp$', column: '100'}])
wrapGuide.updateGuide()
expect(column).toBeGreaterThan(0)
width = editor.charWidth * wrapGuide.defaultColumn
expect(width).toBeGreaterThan(0)
expect(wrapGuide.position().left).toBe(width)
# this is disabled because we no longer support passing config to an extension
# at load time. we need to convert it to use the global config vars.
xit "uses the function from the config data", ->
rootView.find('.wrap-guide').remove()
config =
getGuideColumn: ->
1
atom.loadPackage('wrap-guide', config)
wrapGuide = rootView.find('.wrap-guide').view()
expect(wrapGuide.getGuideColumn).toBe(config.getGuideColumn)
it "hides the guide when the column is less than 1", ->
wrapGuide.getGuideColumn = (path) ->
-1
it "hides the guide when the config column is less than 1", ->
config.set('wrapGuide.columns', [{pattern: 'sample\.js$', column: -1}])
wrapGuide.updateGuide()
expect(wrapGuide).toBeHidden()

View File

@@ -1,21 +1,22 @@
{View} = require 'space-pen'
$ = require 'jquery'
_ = require 'underscore'
module.exports =
class WrapGuide extends View
@activate: (rootView, state, config) ->
@activate: (rootView, state) ->
requireStylesheet 'wrap-guide.css'
for editor in rootView.getEditors()
if rootView.parents('html').length
@appendToEditorPane(rootView, editor, config)
@appendToEditorPane(rootView, editor)
rootView.on 'editor-open', (e, editor) =>
@appendToEditorPane(rootView, editor, config)
@appendToEditorPane(rootView, editor)
@appendToEditorPane: (rootView, editor, config) ->
if underlayer = editor.pane()?.find('.underlayer')
underlayer.append(new WrapGuide(rootView, editor, config))
underlayer.append(new WrapGuide(rootView, editor))
@content: ->
@div class: 'wrap-guide'
@@ -23,17 +24,22 @@ class WrapGuide extends View
getGuideColumn: null
defaultColumn: 80
initialize: (@rootView, @editor, options = {}) =>
if typeof options.getGuideColumn is 'function'
@getGuideColumn = options.getGuideColumn
else
@getGuideColumn = (path, defaultColumn) -> defaultColumn
initialize: (@rootView, @editor) =>
@observeConfig 'editor.fontSize', => @updateGuide()
@subscribe @editor, 'editor-path-change', => @updateGuide()
@subscribe @editor, 'editor:min-width-changed', => @updateGuide()
@subscribe $(window), 'resize', => @updateGuide()
getGuideColumn: (path) ->
customColumns = config.get('wrapGuide.columns')
return @defaultColumn unless _.isArray(customColumns)
for customColumn in customColumns
continue unless _.isObject(customColumn)
regex = customColumn['pattern']
continue unless regex
return parseInt(customColumn['column']) if new RegExp(regex).test(path)
@defaultColumn
updateGuide: ->
column = @getGuideColumn(@editor.getPath(), @defaultColumn)
if column > 0