mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-08-16 06:30:22 +03:00
Bundle status-bar
This commit is contained in:
parent
86c5ca6b35
commit
1ee29a5a21
1
packages/status-bar/.gitattributes
vendored
Normal file
1
packages/status-bar/.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
spec/fixtures/*.js text eol=lf
|
61
packages/status-bar/README.md
Normal file
61
packages/status-bar/README.md
Normal file
@ -0,0 +1,61 @@
|
||||
# Status Bar package
|
||||
|
||||
Display information about the current editor such as cursor position, file path, grammar, current branch, ahead/behind commit counts, and line diff count.
|
||||
|
||||
![](https://f.cloud.github.com/assets/671378/2241819/f8418cb8-9ce5-11e3-87e5-109e965986d0.png)
|
||||
|
||||
## Configuration
|
||||
|
||||
The status bar package accepts the following configuration values:
|
||||
|
||||
* `status-bar.cursorPositionFormat` — A string that describes the format to use for the cursor position status bar tile. It defaults to `%L:%C`. In the format string, `%L` represents the 1-based line number and `%C` represents the 1-based column number.
|
||||
|
||||
* `status-bar.selectionCountFormat` — A string that describes the format to use for the selection count status bar tile. It defaults to `(%L, %C)`. In the format string, `%L` represents the 1-based line count and `%C` represents the 1-based character count.
|
||||
|
||||
## API
|
||||
|
||||
This package provides a service that you can use in other Pulsar packages. To use it, include `status-bar` in the `consumedServices` section of your `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-package",
|
||||
"consumedServices": {
|
||||
"status-bar": {
|
||||
"versions": {
|
||||
"^1.0.0": "consumeStatusBar"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then, in your package's main module, call methods on the service:
|
||||
|
||||
```coffee
|
||||
module.exports =
|
||||
activate: -> # ...
|
||||
|
||||
consumeStatusBar: (statusBar) ->
|
||||
@statusBarTile = statusBar.addLeftTile(item: myElement, priority: 100)
|
||||
|
||||
deactivate: ->
|
||||
# ...
|
||||
@statusBarTile?.destroy()
|
||||
@statusBarTile = null
|
||||
```
|
||||
|
||||
The `status-bar` API has four methods:
|
||||
|
||||
* `addLeftTile({ item, priority })` - Add a tile to the left side of the status bar. Lower priority tiles are placed further to the left.
|
||||
* `addRightTile({ item, priority })` - Add a tile to the right side of the status bar. Lower priority tiles are placed further to the right.
|
||||
|
||||
The `item` parameter to these methods can be a DOM element, a [jQuery object](http://jquery.com), or a model object for which a view provider has been registered in the [the view registry](https://atom.io/docs/api/latest/ViewRegistry).
|
||||
|
||||
* `getLeftTiles()` - Retrieve all of the tiles on the left side of the status bar.
|
||||
* `getRightTiles()` - Retrieve all of the tiles on the right side of the status bar
|
||||
|
||||
All of these methods return `Tile` objects, which have the following methods:
|
||||
|
||||
* `getPriority()` - Retrieve the priority that was assigned to the `Tile` when it was created.
|
||||
* `getItem()` - Retrieve the `Tile`'s item.
|
||||
* `destroy()` - Remove the `Tile` from the status bar.
|
63
packages/status-bar/lib/cursor-position-view.coffee
Normal file
63
packages/status-bar/lib/cursor-position-view.coffee
Normal file
@ -0,0 +1,63 @@
|
||||
{Disposable} = require 'atom'
|
||||
|
||||
module.exports =
|
||||
class CursorPositionView
|
||||
constructor: ->
|
||||
@viewUpdatePending = false
|
||||
|
||||
@element = document.createElement('status-bar-cursor')
|
||||
@element.classList.add('cursor-position', 'inline-block')
|
||||
@goToLineLink = document.createElement('a')
|
||||
@goToLineLink.classList.add('inline-block')
|
||||
@element.appendChild(@goToLineLink)
|
||||
|
||||
@formatString = atom.config.get('status-bar.cursorPositionFormat') ? '%L:%C'
|
||||
|
||||
@activeItemSubscription = atom.workspace.onDidChangeActiveTextEditor (activeEditor) => @subscribeToActiveTextEditor()
|
||||
|
||||
@subscribeToConfig()
|
||||
@subscribeToActiveTextEditor()
|
||||
|
||||
@tooltip = atom.tooltips.add(@element, title: => "Line #{@row}, Column #{@column}")
|
||||
|
||||
@handleClick()
|
||||
|
||||
destroy: ->
|
||||
@activeItemSubscription.dispose()
|
||||
@cursorSubscription?.dispose()
|
||||
@tooltip.dispose()
|
||||
@configSubscription?.dispose()
|
||||
@clickSubscription.dispose()
|
||||
@updateSubscription?.dispose()
|
||||
|
||||
subscribeToActiveTextEditor: ->
|
||||
@cursorSubscription?.dispose()
|
||||
selectionsMarkerLayer = atom.workspace.getActiveTextEditor()?.selectionsMarkerLayer
|
||||
@cursorSubscription = selectionsMarkerLayer?.onDidUpdate(@scheduleUpdate.bind(this))
|
||||
@scheduleUpdate()
|
||||
|
||||
subscribeToConfig: ->
|
||||
@configSubscription?.dispose()
|
||||
@configSubscription = atom.config.observe 'status-bar.cursorPositionFormat', (value) =>
|
||||
@formatString = value ? '%L:%C'
|
||||
@scheduleUpdate()
|
||||
|
||||
handleClick: ->
|
||||
clickHandler = -> atom.commands.dispatch(atom.views.getView(atom.workspace.getActiveTextEditor()), 'go-to-line:toggle')
|
||||
@element.addEventListener('click', clickHandler)
|
||||
@clickSubscription = new Disposable => @element.removeEventListener('click', clickHandler)
|
||||
|
||||
scheduleUpdate: ->
|
||||
return if @viewUpdatePending
|
||||
|
||||
@viewUpdatePending = true
|
||||
@updateSubscription = atom.views.updateDocument =>
|
||||
@viewUpdatePending = false
|
||||
if position = atom.workspace.getActiveTextEditor()?.getCursorBufferPosition()
|
||||
@row = position.row + 1
|
||||
@column = position.column + 1
|
||||
@goToLineLink.textContent = @formatString.replace('%L', @row).replace('%C', @column)
|
||||
@element.classList.remove('hide')
|
||||
else
|
||||
@goToLineLink.textContent = ''
|
||||
@element.classList.add('hide')
|
118
packages/status-bar/lib/file-info-view.coffee
Normal file
118
packages/status-bar/lib/file-info-view.coffee
Normal file
@ -0,0 +1,118 @@
|
||||
{Disposable} = require 'atom'
|
||||
url = require 'url'
|
||||
fs = require 'fs-plus'
|
||||
|
||||
module.exports =
|
||||
class FileInfoView
|
||||
constructor: ->
|
||||
@element = document.createElement('status-bar-file')
|
||||
@element.classList.add('file-info', 'inline-block')
|
||||
|
||||
@currentPath = document.createElement('a')
|
||||
@currentPath.classList.add('current-path')
|
||||
@element.appendChild(@currentPath)
|
||||
@element.currentPath = @currentPath
|
||||
|
||||
@element.getActiveItem = @getActiveItem.bind(this)
|
||||
|
||||
@activeItemSubscription = atom.workspace.getCenter().onDidChangeActivePaneItem =>
|
||||
@subscribeToActiveItem()
|
||||
@subscribeToActiveItem()
|
||||
|
||||
@registerTooltip()
|
||||
clickHandler = (event) =>
|
||||
isShiftClick = event.shiftKey
|
||||
@showCopiedTooltip(isShiftClick)
|
||||
text = @getActiveItemCopyText(isShiftClick)
|
||||
atom.clipboard.write(text)
|
||||
setTimeout =>
|
||||
@clearCopiedTooltip()
|
||||
, 2000
|
||||
|
||||
@element.addEventListener('click', clickHandler)
|
||||
@clickSubscription = new Disposable => @element.removeEventListener('click', clickHandler)
|
||||
|
||||
registerTooltip: ->
|
||||
@tooltip = atom.tooltips.add(@element, title: ->
|
||||
"Click to copy absolute file path (Shift + Click to copy relative path)")
|
||||
|
||||
clearCopiedTooltip: ->
|
||||
@copiedTooltip?.dispose()
|
||||
@registerTooltip()
|
||||
|
||||
showCopiedTooltip: (copyRelativePath) ->
|
||||
@tooltip?.dispose()
|
||||
@copiedTooltip?.dispose()
|
||||
text = @getActiveItemCopyText(copyRelativePath)
|
||||
@copiedTooltip = atom.tooltips.add @element,
|
||||
title: "Copied: #{text}"
|
||||
trigger: 'manual'
|
||||
delay:
|
||||
show: 0
|
||||
|
||||
getActiveItemCopyText: (copyRelativePath) ->
|
||||
activeItem = @getActiveItem()
|
||||
path = activeItem?.getPath?()
|
||||
return activeItem?.getTitle?() or '' if not path?
|
||||
|
||||
# Make sure we try to relativize before parsing URLs.
|
||||
if copyRelativePath
|
||||
relativized = atom.project.relativize(path)
|
||||
if relativized isnt path
|
||||
return relativized
|
||||
|
||||
# An item path could be a url, we only want to copy the `path` part
|
||||
if path?.indexOf('://') > 0
|
||||
path = url.parse(path).path
|
||||
path
|
||||
|
||||
subscribeToActiveItem: ->
|
||||
@modifiedSubscription?.dispose()
|
||||
@titleSubscription?.dispose()
|
||||
|
||||
if activeItem = @getActiveItem()
|
||||
@updateCallback ?= => @update()
|
||||
|
||||
if typeof activeItem.onDidChangeTitle is 'function'
|
||||
@titleSubscription = activeItem.onDidChangeTitle(@updateCallback)
|
||||
else if typeof activeItem.on is 'function'
|
||||
#TODO Remove once title-changed event support is removed
|
||||
activeItem.on('title-changed', @updateCallback)
|
||||
@titleSubscription = dispose: =>
|
||||
activeItem.off?('title-changed', @updateCallback)
|
||||
|
||||
@modifiedSubscription = activeItem.onDidChangeModified?(@updateCallback)
|
||||
|
||||
@update()
|
||||
|
||||
destroy: ->
|
||||
@activeItemSubscription.dispose()
|
||||
@titleSubscription?.dispose()
|
||||
@modifiedSubscription?.dispose()
|
||||
@clickSubscription?.dispose()
|
||||
@copiedTooltip?.dispose()
|
||||
@tooltip?.dispose()
|
||||
|
||||
getActiveItem: ->
|
||||
atom.workspace.getCenter().getActivePaneItem()
|
||||
|
||||
update: ->
|
||||
@updatePathText()
|
||||
@updateBufferHasModifiedText(@getActiveItem()?.isModified?())
|
||||
|
||||
updateBufferHasModifiedText: (isModified) ->
|
||||
if isModified
|
||||
@element.classList.add('buffer-modified')
|
||||
@isModified = true
|
||||
else
|
||||
@element.classList.remove('buffer-modified')
|
||||
@isModified = false
|
||||
|
||||
updatePathText: ->
|
||||
if path = @getActiveItem()?.getPath?()
|
||||
relativized = atom.project.relativize(path)
|
||||
@currentPath.textContent = if relativized? then fs.tildify(relativized) else path
|
||||
else if title = @getActiveItem()?.getTitle?()
|
||||
@currentPath.textContent = title
|
||||
else
|
||||
@currentPath.textContent = ''
|
222
packages/status-bar/lib/git-view.coffee
Normal file
222
packages/status-bar/lib/git-view.coffee
Normal file
@ -0,0 +1,222 @@
|
||||
_ = require "underscore-plus"
|
||||
{CompositeDisposable, GitRepositoryAsync} = require "atom"
|
||||
|
||||
module.exports =
|
||||
class GitView
|
||||
constructor: ->
|
||||
@element = document.createElement('status-bar-git')
|
||||
@element.classList.add('git-view')
|
||||
|
||||
@createBranchArea()
|
||||
@createCommitsArea()
|
||||
@createStatusArea()
|
||||
|
||||
@activeItemSubscription = atom.workspace.getCenter().onDidChangeActivePaneItem =>
|
||||
@subscribeToActiveItem()
|
||||
@projectPathSubscription = atom.project.onDidChangePaths =>
|
||||
@subscribeToRepositories()
|
||||
@subscribeToRepositories()
|
||||
@subscribeToActiveItem()
|
||||
|
||||
createBranchArea: ->
|
||||
@branchArea = document.createElement('div')
|
||||
@branchArea.classList.add('git-branch', 'inline-block')
|
||||
@element.appendChild(@branchArea)
|
||||
@element.branchArea = @branchArea
|
||||
|
||||
branchIcon = document.createElement('span')
|
||||
branchIcon.classList.add('icon', 'icon-git-branch')
|
||||
@branchArea.appendChild(branchIcon)
|
||||
|
||||
@branchLabel = document.createElement('span')
|
||||
@branchLabel.classList.add('branch-label')
|
||||
@branchArea.appendChild(@branchLabel)
|
||||
@element.branchLabel = @branchLabel
|
||||
|
||||
createCommitsArea: ->
|
||||
@commitsArea = document.createElement('div')
|
||||
@commitsArea.classList.add('git-commits', 'inline-block')
|
||||
@element.appendChild(@commitsArea)
|
||||
|
||||
@commitsAhead = document.createElement('span')
|
||||
@commitsAhead.classList.add('icon', 'icon-arrow-up', 'commits-ahead-label')
|
||||
@commitsArea.appendChild(@commitsAhead)
|
||||
|
||||
@commitsBehind = document.createElement('span')
|
||||
@commitsBehind.classList.add('icon', 'icon-arrow-down', 'commits-behind-label')
|
||||
@commitsArea.appendChild(@commitsBehind)
|
||||
|
||||
createStatusArea: ->
|
||||
@gitStatus = document.createElement('div')
|
||||
@gitStatus.classList.add('git-status', 'inline-block')
|
||||
@element.appendChild(@gitStatus)
|
||||
|
||||
@gitStatusIcon = document.createElement('span')
|
||||
@gitStatusIcon.classList.add('icon')
|
||||
@gitStatus.appendChild(@gitStatusIcon)
|
||||
@element.gitStatusIcon = @gitStatusIcon
|
||||
|
||||
subscribeToActiveItem: ->
|
||||
activeItem = @getActiveItem()
|
||||
|
||||
@savedSubscription?.dispose()
|
||||
@savedSubscription = activeItem?.onDidSave? => @update()
|
||||
|
||||
@update()
|
||||
|
||||
subscribeToRepositories: ->
|
||||
@repositorySubscriptions?.dispose()
|
||||
@repositorySubscriptions = new CompositeDisposable
|
||||
|
||||
for repo in atom.project.getRepositories() when repo?
|
||||
@repositorySubscriptions.add repo.onDidChangeStatus ({path, status}) =>
|
||||
@update() if path is @getActiveItemPath()
|
||||
@repositorySubscriptions.add repo.onDidChangeStatuses =>
|
||||
@update()
|
||||
|
||||
destroy: ->
|
||||
@activeItemSubscription?.dispose()
|
||||
@projectPathSubscription?.dispose()
|
||||
@savedSubscription?.dispose()
|
||||
@repositorySubscriptions?.dispose()
|
||||
@branchTooltipDisposable?.dispose()
|
||||
@commitsAheadTooltipDisposable?.dispose()
|
||||
@commitsBehindTooltipDisposable?.dispose()
|
||||
@statusTooltipDisposable?.dispose()
|
||||
|
||||
getActiveItemPath: ->
|
||||
@getActiveItem()?.getPath?()
|
||||
|
||||
getRepositoryForActiveItem: ->
|
||||
[rootDir] = atom.project.relativizePath(@getActiveItemPath())
|
||||
rootDirIndex = atom.project.getPaths().indexOf(rootDir)
|
||||
if rootDirIndex >= 0
|
||||
atom.project.getRepositories()[rootDirIndex]
|
||||
else
|
||||
for repo in atom.project.getRepositories() when repo
|
||||
return repo
|
||||
|
||||
getActiveItem: ->
|
||||
atom.workspace.getCenter().getActivePaneItem()
|
||||
|
||||
update: ->
|
||||
repo = @getRepositoryForActiveItem()
|
||||
@updateBranchText(repo)
|
||||
@updateAheadBehindCount(repo)
|
||||
@updateStatusText(repo)
|
||||
|
||||
updateBranchText: (repo) ->
|
||||
if @showGitInformation(repo)
|
||||
head = repo.getShortHead(@getActiveItemPath())
|
||||
@branchLabel.textContent = head
|
||||
@branchArea.style.display = '' if head
|
||||
@branchTooltipDisposable?.dispose()
|
||||
@branchTooltipDisposable = atom.tooltips.add @branchArea, title: "On branch #{head}"
|
||||
else
|
||||
@branchArea.style.display = 'none'
|
||||
|
||||
showGitInformation: (repo) ->
|
||||
return false unless repo?
|
||||
|
||||
if itemPath = @getActiveItemPath()
|
||||
atom.project.contains(itemPath)
|
||||
else
|
||||
not @getActiveItem()?
|
||||
|
||||
updateAheadBehindCount: (repo) ->
|
||||
unless @showGitInformation(repo)
|
||||
@commitsArea.style.display = 'none'
|
||||
return
|
||||
|
||||
itemPath = @getActiveItemPath()
|
||||
{ahead, behind} = repo.getCachedUpstreamAheadBehindCount(itemPath)
|
||||
if ahead > 0
|
||||
@commitsAhead.textContent = ahead
|
||||
@commitsAhead.style.display = ''
|
||||
@commitsAheadTooltipDisposable?.dispose()
|
||||
@commitsAheadTooltipDisposable = atom.tooltips.add @commitsAhead, title: "#{_.pluralize(ahead, 'commit')} ahead of upstream"
|
||||
else
|
||||
@commitsAhead.style.display = 'none'
|
||||
|
||||
if behind > 0
|
||||
@commitsBehind.textContent = behind
|
||||
@commitsBehind.style.display = ''
|
||||
@commitsBehindTooltipDisposable?.dispose()
|
||||
@commitsBehindTooltipDisposable = atom.tooltips.add @commitsBehind, title: "#{_.pluralize(behind, 'commit')} behind upstream"
|
||||
else
|
||||
@commitsBehind.style.display = 'none'
|
||||
|
||||
if ahead > 0 or behind > 0
|
||||
@commitsArea.style.display = ''
|
||||
else
|
||||
@commitsArea.style.display = 'none'
|
||||
|
||||
clearStatus: ->
|
||||
@gitStatusIcon.classList.remove('icon-diff-modified', 'status-modified', 'icon-diff-added', 'status-added', 'icon-diff-ignored', 'status-ignored')
|
||||
|
||||
updateAsNewFile: ->
|
||||
@clearStatus()
|
||||
|
||||
@gitStatusIcon.classList.add('icon-diff-added', 'status-added')
|
||||
if textEditor = atom.workspace.getActiveTextEditor()
|
||||
@gitStatusIcon.textContent = "+#{textEditor.getLineCount()}"
|
||||
@updateTooltipText("#{_.pluralize(textEditor.getLineCount(), 'line')} in this new file not yet committed")
|
||||
else
|
||||
@gitStatusIcon.textContent = ''
|
||||
@updateTooltipText()
|
||||
|
||||
@gitStatus.style.display = ''
|
||||
|
||||
updateAsModifiedFile: (repo, path) ->
|
||||
stats = repo.getDiffStats(path)
|
||||
@clearStatus()
|
||||
|
||||
@gitStatusIcon.classList.add('icon-diff-modified', 'status-modified')
|
||||
if stats.added and stats.deleted
|
||||
@gitStatusIcon.textContent = "+#{stats.added}, -#{stats.deleted}"
|
||||
@updateTooltipText("#{_.pluralize(stats.added, 'line')} added and #{_.pluralize(stats.deleted, 'line')} deleted in this file not yet committed")
|
||||
else if stats.added
|
||||
@gitStatusIcon.textContent = "+#{stats.added}"
|
||||
@updateTooltipText("#{_.pluralize(stats.added, 'line')} added to this file not yet committed")
|
||||
else if stats.deleted
|
||||
@gitStatusIcon.textContent = "-#{stats.deleted}"
|
||||
@updateTooltipText("#{_.pluralize(stats.deleted, 'line')} deleted from this file not yet committed")
|
||||
else
|
||||
@gitStatusIcon.textContent = ''
|
||||
@updateTooltipText()
|
||||
|
||||
@gitStatus.style.display = ''
|
||||
|
||||
updateAsIgnoredFile: ->
|
||||
@clearStatus()
|
||||
|
||||
@gitStatusIcon.classList.add('icon-diff-ignored', 'status-ignored')
|
||||
@gitStatusIcon.textContent = ''
|
||||
@gitStatus.style.display = ''
|
||||
@updateTooltipText("File is ignored by git")
|
||||
|
||||
updateTooltipText: (text) ->
|
||||
@statusTooltipDisposable?.dispose()
|
||||
if text
|
||||
@statusTooltipDisposable = atom.tooltips.add @gitStatusIcon, title: text
|
||||
|
||||
updateStatusText: (repo) ->
|
||||
hideStatus = =>
|
||||
@clearStatus()
|
||||
@gitStatus.style.display = 'none'
|
||||
|
||||
itemPath = @getActiveItemPath()
|
||||
if @showGitInformation(repo) and itemPath?
|
||||
status = repo.getCachedPathStatus(itemPath) ? 0
|
||||
if repo.isStatusNew(status)
|
||||
return @updateAsNewFile()
|
||||
|
||||
if repo.isStatusModified(status)
|
||||
return @updateAsModifiedFile(repo, itemPath)
|
||||
|
||||
if repo.isPathIgnored(itemPath)
|
||||
@updateAsIgnoredFile()
|
||||
else
|
||||
hideStatus()
|
||||
else
|
||||
hideStatus()
|
14
packages/status-bar/lib/launch-mode-view.coffee
Normal file
14
packages/status-bar/lib/launch-mode-view.coffee
Normal file
@ -0,0 +1,14 @@
|
||||
module.exports =
|
||||
class LaunchModeView
|
||||
constructor: ({safeMode, devMode}={}) ->
|
||||
@element = document.createElement('status-bar-launch-mode')
|
||||
@element.classList.add('inline-block', 'icon', 'icon-color-mode')
|
||||
if devMode
|
||||
@element.classList.add('text-error')
|
||||
@tooltipDisposable = atom.tooltips.add(@element, title: 'This window is in dev mode')
|
||||
else if safeMode
|
||||
@element.classList.add('text-success')
|
||||
@tooltipDisposable = atom.tooltips.add(@element, title: 'This window is in safe mode')
|
||||
|
||||
detachedCallback: ->
|
||||
@tooltipDisposable?.dispose()
|
121
packages/status-bar/lib/main.coffee
Normal file
121
packages/status-bar/lib/main.coffee
Normal file
@ -0,0 +1,121 @@
|
||||
{CompositeDisposable, Emitter} = require 'atom'
|
||||
Grim = require 'grim'
|
||||
StatusBarView = require './status-bar-view'
|
||||
FileInfoView = require './file-info-view'
|
||||
CursorPositionView = require './cursor-position-view'
|
||||
SelectionCountView = require './selection-count-view'
|
||||
GitView = require './git-view'
|
||||
LaunchModeView = require './launch-mode-view'
|
||||
|
||||
module.exports =
|
||||
activate: ->
|
||||
@emitters = new Emitter()
|
||||
@subscriptions = new CompositeDisposable()
|
||||
|
||||
@statusBar = new StatusBarView()
|
||||
@attachStatusBar()
|
||||
|
||||
@subscriptions.add atom.config.onDidChange 'status-bar.fullWidth', =>
|
||||
@attachStatusBar()
|
||||
|
||||
@updateStatusBarVisibility()
|
||||
|
||||
@statusBarVisibilitySubscription =
|
||||
atom.config.observe 'status-bar.isVisible', =>
|
||||
@updateStatusBarVisibility()
|
||||
|
||||
atom.commands.add 'atom-workspace', 'status-bar:toggle', =>
|
||||
if @statusBarPanel.isVisible()
|
||||
atom.config.set 'status-bar.isVisible', false
|
||||
else
|
||||
atom.config.set 'status-bar.isVisible', true
|
||||
|
||||
{safeMode, devMode} = atom.getLoadSettings()
|
||||
if safeMode or devMode
|
||||
launchModeView = new LaunchModeView({safeMode, devMode})
|
||||
@statusBar.addLeftTile(item: launchModeView.element, priority: -1)
|
||||
|
||||
@fileInfo = new FileInfoView()
|
||||
@statusBar.addLeftTile(item: @fileInfo.element, priority: 0)
|
||||
|
||||
@cursorPosition = new CursorPositionView()
|
||||
@statusBar.addLeftTile(item: @cursorPosition.element, priority: 1)
|
||||
|
||||
@selectionCount = new SelectionCountView()
|
||||
@statusBar.addLeftTile(item: @selectionCount.element, priority: 2)
|
||||
|
||||
@gitInfo = new GitView()
|
||||
@gitInfoTile = @statusBar.addRightTile(item: @gitInfo.element, priority: 0)
|
||||
|
||||
deactivate: ->
|
||||
@statusBarVisibilitySubscription?.dispose()
|
||||
@statusBarVisibilitySubscription = null
|
||||
|
||||
@gitInfo?.destroy()
|
||||
@gitInfo = null
|
||||
|
||||
@fileInfo?.destroy()
|
||||
@fileInfo = null
|
||||
|
||||
@cursorPosition?.destroy()
|
||||
@cursorPosition = null
|
||||
|
||||
@selectionCount?.destroy()
|
||||
@selectionCount = null
|
||||
|
||||
@statusBarPanel?.destroy()
|
||||
@statusBarPanel = null
|
||||
|
||||
@statusBar?.destroy()
|
||||
@statusBar = null
|
||||
|
||||
@subscriptions?.dispose()
|
||||
@subscriptions = null
|
||||
|
||||
@emitters?.dispose()
|
||||
@emitters = null
|
||||
|
||||
delete atom.__workspaceView.statusBar if atom.__workspaceView?
|
||||
|
||||
updateStatusBarVisibility: ->
|
||||
if atom.config.get 'status-bar.isVisible'
|
||||
@statusBarPanel.show()
|
||||
else
|
||||
@statusBarPanel.hide()
|
||||
|
||||
provideStatusBar: ->
|
||||
addLeftTile: @statusBar.addLeftTile.bind(@statusBar)
|
||||
addRightTile: @statusBar.addRightTile.bind(@statusBar)
|
||||
getLeftTiles: @statusBar.getLeftTiles.bind(@statusBar)
|
||||
getRightTiles: @statusBar.getRightTiles.bind(@statusBar)
|
||||
disableGitInfoTile: @gitInfoTile.destroy.bind(@gitInfoTile)
|
||||
|
||||
attachStatusBar: ->
|
||||
@statusBarPanel.destroy() if @statusBarPanel?
|
||||
|
||||
panelArgs = {item: @statusBar, priority: 0}
|
||||
if atom.config.get('status-bar.fullWidth')
|
||||
@statusBarPanel = atom.workspace.addFooterPanel panelArgs
|
||||
else
|
||||
@statusBarPanel = atom.workspace.addBottomPanel panelArgs
|
||||
|
||||
# Deprecated
|
||||
#
|
||||
# Wrap deprecation calls on the methods returned rather than
|
||||
# Services API method which would be registered and trigger
|
||||
# a deprecation call
|
||||
legacyProvideStatusBar: ->
|
||||
statusbar = @provideStatusBar()
|
||||
|
||||
addLeftTile: (args...) ->
|
||||
Grim.deprecate("Use version ^1.0.0 of the status-bar Service API.")
|
||||
statusbar.addLeftTile(args...)
|
||||
addRightTile: (args...) ->
|
||||
Grim.deprecate("Use version ^1.0.0 of the status-bar Service API.")
|
||||
statusbar.addRightTile(args...)
|
||||
getLeftTiles: ->
|
||||
Grim.deprecate("Use version ^1.0.0 of the status-bar Service API.")
|
||||
statusbar.getLeftTiles()
|
||||
getRightTiles: ->
|
||||
Grim.deprecate("Use version ^1.0.0 of the status-bar Service API.")
|
||||
statusbar.getRightTiles()
|
58
packages/status-bar/lib/selection-count-view.coffee
Normal file
58
packages/status-bar/lib/selection-count-view.coffee
Normal file
@ -0,0 +1,58 @@
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
module.exports =
|
||||
class SelectionCountView
|
||||
constructor: ->
|
||||
@element = document.createElement('status-bar-selection')
|
||||
@element.classList.add('selection-count', 'inline-block')
|
||||
|
||||
@tooltipElement = document.createElement('div')
|
||||
@tooltipDisposable = atom.tooltips.add @element, item: @tooltipElement
|
||||
|
||||
@formatString = atom.config.get('status-bar.selectionCountFormat') ? '(%L, %C)'
|
||||
|
||||
@activeItemSubscription = atom.workspace.onDidChangeActiveTextEditor => @subscribeToActiveTextEditor()
|
||||
|
||||
@subscribeToConfig()
|
||||
@subscribeToActiveTextEditor()
|
||||
|
||||
destroy: ->
|
||||
@activeItemSubscription.dispose()
|
||||
@selectionSubscription?.dispose()
|
||||
@configSubscription?.dispose()
|
||||
@tooltipDisposable.dispose()
|
||||
|
||||
subscribeToConfig: ->
|
||||
@configSubscription?.dispose()
|
||||
@configSubscription = atom.config.observe 'status-bar.selectionCountFormat', (value) =>
|
||||
@formatString = value ? '(%L, %C)'
|
||||
@scheduleUpdateCount()
|
||||
|
||||
subscribeToActiveTextEditor: ->
|
||||
@selectionSubscription?.dispose()
|
||||
activeEditor = @getActiveTextEditor()
|
||||
selectionsMarkerLayer = activeEditor?.selectionsMarkerLayer
|
||||
@selectionSubscription = selectionsMarkerLayer?.onDidUpdate(@scheduleUpdateCount.bind(this))
|
||||
@scheduleUpdateCount()
|
||||
|
||||
getActiveTextEditor: ->
|
||||
atom.workspace.getActiveTextEditor()
|
||||
|
||||
scheduleUpdateCount: ->
|
||||
unless @scheduledUpdate
|
||||
@scheduledUpdate = true
|
||||
atom.views.updateDocument =>
|
||||
@updateCount()
|
||||
@scheduledUpdate = false
|
||||
|
||||
updateCount: ->
|
||||
count = @getActiveTextEditor()?.getSelectedText().length
|
||||
range = @getActiveTextEditor()?.getSelectedBufferRange()
|
||||
lineCount = range?.getRowCount()
|
||||
lineCount -= 1 if range?.end.column is 0
|
||||
if count > 0
|
||||
@element.textContent = @formatString.replace('%L', lineCount).replace('%C', count)
|
||||
@tooltipElement.textContent = "#{_.pluralize(lineCount, 'line')}, #{_.pluralize(count, 'character')} selected"
|
||||
else
|
||||
@element.textContent = ''
|
||||
@tooltipElement.textContent = ''
|
107
packages/status-bar/lib/status-bar-view.coffee
Normal file
107
packages/status-bar/lib/status-bar-view.coffee
Normal file
@ -0,0 +1,107 @@
|
||||
{Disposable} = require 'atom'
|
||||
Tile = require './tile'
|
||||
|
||||
module.exports =
|
||||
class StatusBarView
|
||||
constructor: ->
|
||||
@element = document.createElement('status-bar')
|
||||
@element.classList.add('status-bar')
|
||||
|
||||
flexboxHackElement = document.createElement('div')
|
||||
flexboxHackElement.classList.add('flexbox-repaint-hack')
|
||||
@element.appendChild(flexboxHackElement)
|
||||
|
||||
@leftPanel = document.createElement('div')
|
||||
@leftPanel.classList.add('status-bar-left')
|
||||
flexboxHackElement.appendChild(@leftPanel)
|
||||
@element.leftPanel = @leftPanel
|
||||
|
||||
@rightPanel = document.createElement('div')
|
||||
@rightPanel.classList.add('status-bar-right')
|
||||
flexboxHackElement.appendChild(@rightPanel)
|
||||
@element.rightPanel = @rightPanel
|
||||
|
||||
@leftTiles = []
|
||||
@rightTiles = []
|
||||
|
||||
@element.getLeftTiles = @getLeftTiles.bind(this)
|
||||
@element.getRightTiles = @getRightTiles.bind(this)
|
||||
@element.addLeftTile = @addLeftTile.bind(this)
|
||||
@element.addRightTile = @addRightTile.bind(this)
|
||||
|
||||
@bufferSubscriptions = []
|
||||
|
||||
@activeItemSubscription = atom.workspace.getCenter().onDidChangeActivePaneItem =>
|
||||
@unsubscribeAllFromBuffer()
|
||||
@storeActiveBuffer()
|
||||
@subscribeAllToBuffer()
|
||||
|
||||
@element.dispatchEvent(new CustomEvent('active-buffer-changed', bubbles: true))
|
||||
|
||||
@storeActiveBuffer()
|
||||
|
||||
destroy: ->
|
||||
@activeItemSubscription.dispose()
|
||||
@unsubscribeAllFromBuffer()
|
||||
@element.remove()
|
||||
|
||||
addLeftTile: (options) ->
|
||||
newItem = options.item
|
||||
newPriority = options?.priority ? @leftTiles[@leftTiles.length - 1].priority + 1
|
||||
nextItem = null
|
||||
for {priority, item}, index in @leftTiles
|
||||
if priority > newPriority
|
||||
nextItem = item
|
||||
break
|
||||
|
||||
newTile = new Tile(newItem, newPriority, @leftTiles)
|
||||
@leftTiles.splice(index, 0, newTile)
|
||||
newElement = atom.views.getView(newItem)
|
||||
nextElement = atom.views.getView(nextItem)
|
||||
@leftPanel.insertBefore(newElement, nextElement)
|
||||
newTile
|
||||
|
||||
addRightTile: (options) ->
|
||||
newItem = options.item
|
||||
newPriority = options?.priority ? @rightTiles[0].priority + 1
|
||||
nextItem = null
|
||||
for {priority, item}, index in @rightTiles
|
||||
if priority < newPriority
|
||||
nextItem = item
|
||||
break
|
||||
|
||||
newTile = new Tile(newItem, newPriority, @rightTiles)
|
||||
@rightTiles.splice(index, 0, newTile)
|
||||
newElement = atom.views.getView(newItem)
|
||||
nextElement = atom.views.getView(nextItem)
|
||||
@rightPanel.insertBefore(newElement, nextElement)
|
||||
newTile
|
||||
|
||||
getLeftTiles: ->
|
||||
@leftTiles
|
||||
|
||||
getRightTiles: ->
|
||||
@rightTiles
|
||||
|
||||
getActiveBuffer: ->
|
||||
@buffer
|
||||
|
||||
getActiveItem: ->
|
||||
atom.workspace.getCenter().getActivePaneItem()
|
||||
|
||||
storeActiveBuffer: ->
|
||||
@buffer = @getActiveItem()?.getBuffer?()
|
||||
|
||||
subscribeToBuffer: (event, callback) ->
|
||||
@bufferSubscriptions.push([event, callback])
|
||||
@buffer.on(event, callback) if @buffer
|
||||
|
||||
subscribeAllToBuffer: ->
|
||||
return unless @buffer
|
||||
for [event, callback] in @bufferSubscriptions
|
||||
@buffer.on(event, callback)
|
||||
|
||||
unsubscribeAllFromBuffer: ->
|
||||
return unless @buffer
|
||||
for [event, callback] in @bufferSubscriptions
|
||||
@buffer.off(event, callback)
|
13
packages/status-bar/lib/tile.coffee
Normal file
13
packages/status-bar/lib/tile.coffee
Normal file
@ -0,0 +1,13 @@
|
||||
module.exports =
|
||||
class Tile
|
||||
constructor: (@item, @priority, @collection) ->
|
||||
|
||||
getItem: ->
|
||||
@item
|
||||
|
||||
getPriority: ->
|
||||
@priority
|
||||
|
||||
destroy: ->
|
||||
@collection.splice(@collection.indexOf(this), 1)
|
||||
atom.views.getView(@item).remove()
|
177
packages/status-bar/package-lock.json
generated
Normal file
177
packages/status-bar/package-lock.json
generated
Normal file
@ -0,0 +1,177 @@
|
||||
{
|
||||
"name": "status-bar",
|
||||
"version": "1.8.17",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "status-bar",
|
||||
"version": "1.8.17",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fs-plus": "^3.0.1",
|
||||
"grim": "^2.0.1",
|
||||
"underscore-plus": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"atom": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/async": {
|
||||
"version": "1.5.2",
|
||||
"resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz",
|
||||
"integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||
},
|
||||
"node_modules/event-kit": {
|
||||
"version": "2.5.3",
|
||||
"resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.5.3.tgz",
|
||||
"integrity": "sha512-b7Qi1JNzY4BfAYfnIRanLk0DOD1gdkWHT4GISIn8Q2tAf3LpU8SP2CMwWaq40imYoKWbtN4ZhbSRxvsnikooZQ=="
|
||||
},
|
||||
"node_modules/fs-plus": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/fs-plus/-/fs-plus-3.0.2.tgz",
|
||||
"integrity": "sha1-a19Sp3EolMTd6f2PgfqMYN8EHz0=",
|
||||
"dependencies": {
|
||||
"async": "^1.5.2",
|
||||
"mkdirp": "^0.5.1",
|
||||
"rimraf": "^2.5.2",
|
||||
"underscore-plus": "1.x"
|
||||
}
|
||||
},
|
||||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
|
||||
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/grim": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/grim/-/grim-2.0.2.tgz",
|
||||
"integrity": "sha512-Qj7hTJRfd87E/gUgfvM0YIH/g2UA2SV6niv6BYXk1o6w4mhgv+QyYM1EjOJQljvzgEj4SqSsRWldXIeKHz3e3Q==",
|
||||
"dependencies": {
|
||||
"event-kit": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"dependencies": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
|
||||
},
|
||||
"node_modules/mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||
"deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)",
|
||||
"dependencies": {
|
||||
"minimist": "0.0.8"
|
||||
},
|
||||
"bin": {
|
||||
"mkdirp": "bin/cmd.js"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rimraf": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
|
||||
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
|
||||
"dependencies": {
|
||||
"glob": "^7.0.5"
|
||||
},
|
||||
"bin": {
|
||||
"rimraf": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/underscore": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "http://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
|
||||
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
|
||||
},
|
||||
"node_modules/underscore-plus": {
|
||||
"version": "1.6.8",
|
||||
"resolved": "https://registry.npmjs.org/underscore-plus/-/underscore-plus-1.6.8.tgz",
|
||||
"integrity": "sha512-88PrCeMKeAAC1L4xjSiiZ3Fg6kZOYrLpLGVPPeqKq/662DfQe/KTSKdSR/Q/tucKNnfW2MNAUGSCkDf8HmXC5Q==",
|
||||
"dependencies": {
|
||||
"underscore": "~1.8.3"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
}
|
||||
}
|
||||
}
|
51
packages/status-bar/package.json
Normal file
51
packages/status-bar/package.json
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "status-bar",
|
||||
"version": "1.8.17",
|
||||
"main": "./lib/main",
|
||||
"description": "Display information about the current editor such as cursor position, file path, grammar, current branch, ahead/behind commits counts, and line diff count.",
|
||||
"repository": "https://github.com/pulsar-edit/pulsar",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"atom": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"fs-plus": "^3.0.1",
|
||||
"grim": "^2.0.1",
|
||||
"underscore-plus": "^1.0.0"
|
||||
},
|
||||
"providedServices": {
|
||||
"status-bar": {
|
||||
"description": "A container for indicators at the bottom of the workspace",
|
||||
"versions": {
|
||||
"1.1.0": "provideStatusBar",
|
||||
"0.58.0": "legacyProvideStatusBar"
|
||||
}
|
||||
}
|
||||
},
|
||||
"configSchema": {
|
||||
"isVisible": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Show status bar at the bottom of the workspace"
|
||||
},
|
||||
"fullWidth": {
|
||||
"order": 1,
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"title": "Full-width",
|
||||
"description": "Fit the status-bar to the window's full-width"
|
||||
},
|
||||
"cursorPositionFormat": {
|
||||
"order": 2,
|
||||
"type": "string",
|
||||
"default": "%L:%C",
|
||||
"description": "Format for the cursor position status bar element, where %L is the line number and %C is the column number"
|
||||
},
|
||||
"selectionCountFormat": {
|
||||
"order": 2,
|
||||
"type": "string",
|
||||
"default": "(%L, %C)",
|
||||
"description": "Format for the selection count status bar element, where %L is the line count and %C is the character count"
|
||||
}
|
||||
}
|
||||
}
|
659
packages/status-bar/spec/built-in-tiles-spec.coffee
Normal file
659
packages/status-bar/spec/built-in-tiles-spec.coffee
Normal file
@ -0,0 +1,659 @@
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
os = require 'os'
|
||||
process = require 'process'
|
||||
|
||||
describe "Built-in Status Bar Tiles", ->
|
||||
[statusBar, workspaceElement, dummyView] = []
|
||||
|
||||
beforeEach ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
dummyView = document.createElement("div")
|
||||
statusBar = null
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('status-bar')
|
||||
|
||||
runs ->
|
||||
statusBar = workspaceElement.querySelector("status-bar")
|
||||
|
||||
describe "the file info, cursor and selection tiles", ->
|
||||
[editor, buffer, fileInfo, cursorPosition, selectionCount] = []
|
||||
|
||||
beforeEach ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js')
|
||||
|
||||
runs ->
|
||||
[launchMode, fileInfo, cursorPosition, selectionCount] =
|
||||
statusBar.getLeftTiles().map (tile) -> tile.getItem()
|
||||
editor = atom.workspace.getActiveTextEditor()
|
||||
buffer = editor.getBuffer()
|
||||
|
||||
describe "when associated with an unsaved buffer", ->
|
||||
it "displays 'untitled' instead of the buffer's path, but still displays the buffer position", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open()
|
||||
|
||||
runs ->
|
||||
atom.views.performDocumentUpdate()
|
||||
expect(fileInfo.currentPath.textContent).toBe 'untitled'
|
||||
expect(cursorPosition.textContent).toBe '1:1'
|
||||
expect(selectionCount).toBeHidden()
|
||||
|
||||
describe "when the associated editor's path changes", ->
|
||||
it "updates the path in the status bar", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.txt')
|
||||
|
||||
runs ->
|
||||
expect(fileInfo.currentPath.textContent).toBe 'sample.txt'
|
||||
|
||||
describe "when associated with remote file path", ->
|
||||
beforeEach ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
dummyView.getPath = -> 'remote://server:123/folder/remote_file.txt'
|
||||
atom.workspace.getActivePane().activateItem(dummyView)
|
||||
|
||||
it "updates the path in the status bar", ->
|
||||
# The remote path isn't relativized in the test because no remote directory provider is registered.
|
||||
expect(fileInfo.currentPath.textContent).toBe 'remote://server:123/folder/remote_file.txt'
|
||||
expect(fileInfo.currentPath).toBeVisible()
|
||||
|
||||
it "when the path is clicked", ->
|
||||
fileInfo.currentPath.click()
|
||||
expect(atom.clipboard.read()).toBe '/folder/remote_file.txt'
|
||||
|
||||
it "calls relativize with the remote URL on shift-click", ->
|
||||
spy = spyOn(atom.project, 'relativize').andReturn 'remote_file.txt'
|
||||
event = new MouseEvent('click', shiftKey: true)
|
||||
fileInfo.dispatchEvent(event)
|
||||
expect(atom.clipboard.read()).toBe 'remote_file.txt'
|
||||
expect(spy).toHaveBeenCalledWith 'remote://server:123/folder/remote_file.txt'
|
||||
|
||||
describe "when file info tile is clicked", ->
|
||||
it "copies the absolute path into the clipboard if available", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.txt')
|
||||
|
||||
runs ->
|
||||
fileInfo.click()
|
||||
expect(atom.clipboard.read()).toBe fileInfo.getActiveItem().getPath()
|
||||
|
||||
describe "when the file info tile is shift-clicked", ->
|
||||
it "copies the relative path into the clipboard if available", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.txt')
|
||||
|
||||
runs ->
|
||||
event = new MouseEvent('click', shiftKey: true)
|
||||
fileInfo.dispatchEvent(event)
|
||||
expect(atom.clipboard.read()).toBe 'sample.txt'
|
||||
|
||||
describe "when path of an unsaved buffer is clicked", ->
|
||||
it "copies the 'untitled' into clipboard", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open()
|
||||
|
||||
runs ->
|
||||
fileInfo.currentPath.click()
|
||||
expect(atom.clipboard.read()).toBe 'untitled'
|
||||
|
||||
describe "when buffer's path is not clicked", ->
|
||||
it "doesn't display a path tooltip", ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
waitsForPromise ->
|
||||
atom.workspace.open()
|
||||
|
||||
runs ->
|
||||
expect(document.querySelector('.tooltip')).not.toExist()
|
||||
|
||||
describe "when buffer's path is clicked", ->
|
||||
it "displays path tooltip and the tooltip disappears after ~2 seconds", ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
waitsForPromise ->
|
||||
atom.workspace.open()
|
||||
|
||||
runs ->
|
||||
fileInfo.currentPath.click()
|
||||
expect(document.querySelector('.tooltip')).toBeVisible()
|
||||
# extra leeway so test won't fail because tooltip disappeared few milliseconds too late
|
||||
advanceClock(2100)
|
||||
expect(document.querySelector('.tooltip')).not.toExist()
|
||||
|
||||
describe "when saved buffer's path is clicked", ->
|
||||
it "displays a tooltip containing text 'Copied:' and an absolute native path", ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.txt')
|
||||
|
||||
runs ->
|
||||
fileInfo.currentPath.click()
|
||||
expect(document.querySelector('.tooltip')).toHaveText "Copied: #{fileInfo.getActiveItem().getPath()}"
|
||||
|
||||
it "displays a tooltip containing text 'Copied:' for an absolute Unix path", ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
dummyView.getPath = -> '/user/path/for/my/file.txt'
|
||||
atom.workspace.getActivePane().activateItem(dummyView)
|
||||
|
||||
runs ->
|
||||
fileInfo.currentPath.click()
|
||||
expect(document.querySelector('.tooltip')).toHaveText "Copied: #{dummyView.getPath()}"
|
||||
|
||||
it "displays a tooltip containing text 'Copied:' for an absolute Windows path", ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
dummyView.getPath = -> 'c:\\user\\path\\for\\my\\file.txt'
|
||||
atom.workspace.getActivePane().activateItem(dummyView)
|
||||
|
||||
runs ->
|
||||
fileInfo.currentPath.click()
|
||||
expect(document.querySelector('.tooltip')).toHaveText "Copied: #{dummyView.getPath()}"
|
||||
|
||||
describe "when unsaved buffer's path is clicked", ->
|
||||
it "displays a tooltip containing text 'Copied: untitled", ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
waitsForPromise ->
|
||||
atom.workspace.open()
|
||||
|
||||
runs ->
|
||||
fileInfo.currentPath.click()
|
||||
expect(document.querySelector('.tooltip')).toHaveText "Copied: untitled"
|
||||
|
||||
describe "when the associated editor's buffer's content changes", ->
|
||||
it "enables the buffer modified indicator", ->
|
||||
expect(fileInfo.classList.contains('buffer-modified')).toBe(false)
|
||||
editor.insertText("\n")
|
||||
advanceClock(buffer.stoppedChangingDelay)
|
||||
expect(fileInfo.classList.contains('buffer-modified')).toBe(true)
|
||||
editor.backspace()
|
||||
|
||||
describe "when the buffer content has changed from the content on disk", ->
|
||||
it "disables the buffer modified indicator on save", ->
|
||||
filePath = path.join(os.tmpdir(), "atom-whitespace.txt")
|
||||
fs.writeFileSync(filePath, "")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath)
|
||||
|
||||
runs ->
|
||||
editor = atom.workspace.getActiveTextEditor()
|
||||
expect(fileInfo.classList.contains('buffer-modified')).toBe(false)
|
||||
editor.insertText("\n")
|
||||
advanceClock(buffer.stoppedChangingDelay)
|
||||
expect(fileInfo.classList.contains('buffer-modified')).toBe(true)
|
||||
|
||||
waitsForPromise ->
|
||||
# TODO - remove this Promise.resolve once atom/atom#14435 lands.
|
||||
Promise.resolve(editor.getBuffer().save())
|
||||
|
||||
runs ->
|
||||
expect(fileInfo.classList.contains('buffer-modified')).toBe(false)
|
||||
|
||||
it "disables the buffer modified indicator if the content matches again", ->
|
||||
expect(fileInfo.classList.contains('buffer-modified')).toBe(false)
|
||||
editor.insertText("\n")
|
||||
advanceClock(buffer.stoppedChangingDelay)
|
||||
expect(fileInfo.classList.contains('buffer-modified')).toBe(true)
|
||||
editor.backspace()
|
||||
advanceClock(buffer.stoppedChangingDelay)
|
||||
expect(fileInfo.classList.contains('buffer-modified')).toBe(false)
|
||||
|
||||
it "disables the buffer modified indicator when the change is undone", ->
|
||||
expect(fileInfo.classList.contains('buffer-modified')).toBe(false)
|
||||
editor.insertText("\n")
|
||||
advanceClock(buffer.stoppedChangingDelay)
|
||||
expect(fileInfo.classList.contains('buffer-modified')).toBe(true)
|
||||
editor.undo()
|
||||
advanceClock(buffer.stoppedChangingDelay)
|
||||
expect(fileInfo.classList.contains('buffer-modified')).toBe(false)
|
||||
|
||||
describe "when the buffer changes", ->
|
||||
it "updates the buffer modified indicator for the new buffer", ->
|
||||
expect(fileInfo.classList.contains('buffer-modified')).toBe(false)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.txt')
|
||||
|
||||
runs ->
|
||||
editor = atom.workspace.getActiveTextEditor()
|
||||
editor.insertText("\n")
|
||||
advanceClock(buffer.stoppedChangingDelay)
|
||||
expect(fileInfo.classList.contains('buffer-modified')).toBe(true)
|
||||
|
||||
it "doesn't update the buffer modified indicator for the old buffer", ->
|
||||
oldBuffer = editor.getBuffer()
|
||||
expect(fileInfo.classList.contains('buffer-modified')).toBe(false)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.txt')
|
||||
|
||||
runs ->
|
||||
oldBuffer.setText("new text")
|
||||
advanceClock(buffer.stoppedChangingDelay)
|
||||
expect(fileInfo.classList.contains('buffer-modified')).toBe(false)
|
||||
|
||||
describe "when the associated editor's cursor position changes", ->
|
||||
it "updates the cursor position in the status bar", ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
editor.setCursorScreenPosition([1, 2])
|
||||
atom.views.performDocumentUpdate()
|
||||
expect(cursorPosition.textContent).toBe '2:3'
|
||||
|
||||
it "does not throw an exception if the cursor is moved as the result of the active pane item changing to a non-editor (regression)", ->
|
||||
waitsForPromise ->
|
||||
Promise.resolve(atom.packages.deactivatePackage('status-bar')) # Wrapped so works with Promise & non-Promise deactivate
|
||||
runs ->
|
||||
atom.workspace.onDidChangeActivePaneItem(-> editor.setCursorScreenPosition([1, 2]))
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('status-bar')
|
||||
runs ->
|
||||
statusBar = workspaceElement.querySelector("status-bar")
|
||||
cursorPosition = statusBar.getLeftTiles()[2].getItem()
|
||||
|
||||
atom.workspace.getActivePane().activateItem(document.createElement('div'))
|
||||
expect(editor.getCursorScreenPosition()).toEqual([1, 2])
|
||||
atom.views.performDocumentUpdate()
|
||||
expect(cursorPosition).toBeHidden()
|
||||
|
||||
describe "when the associated editor's selection changes", ->
|
||||
it "updates the selection count in the status bar", ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
|
||||
editor.setSelectedBufferRange([[0, 0], [0, 0]])
|
||||
atom.views.performDocumentUpdate()
|
||||
expect(selectionCount.textContent).toBe ''
|
||||
|
||||
editor.setSelectedBufferRange([[0, 0], [0, 2]])
|
||||
atom.views.performDocumentUpdate()
|
||||
expect(selectionCount.textContent).toBe '(1, 2)'
|
||||
|
||||
editor.setSelectedBufferRange([[0, 0], [1, 30]])
|
||||
atom.views.performDocumentUpdate()
|
||||
expect(selectionCount.textContent).toBe "(2, 60)"
|
||||
|
||||
it "does not throw an exception if the cursor is moved as the result of the active pane item changing to a non-editor (regression)", ->
|
||||
waitsForPromise ->
|
||||
Promise.resolve(atom.packages.deactivatePackage('status-bar')) # Wrapped so works with Promise & non-Promise deactivate
|
||||
runs ->
|
||||
atom.workspace.onDidChangeActivePaneItem(-> editor.setSelectedBufferRange([[1, 2], [1, 3]]))
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('status-bar')
|
||||
runs ->
|
||||
statusBar = workspaceElement.querySelector("status-bar")
|
||||
selectionCount = statusBar.getLeftTiles()[3].getItem()
|
||||
|
||||
atom.workspace.getActivePane().activateItem(document.createElement('div'))
|
||||
expect(editor.getSelectedBufferRange()).toEqual([[1, 2], [1, 3]])
|
||||
atom.views.performDocumentUpdate()
|
||||
expect(selectionCount).toBeHidden()
|
||||
|
||||
describe "when the active pane item does not implement getCursorBufferPosition()", ->
|
||||
it "hides the cursor position view", ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
atom.workspace.getActivePane().activateItem(dummyView)
|
||||
atom.views.performDocumentUpdate()
|
||||
expect(cursorPosition).toBeHidden()
|
||||
|
||||
describe "when the active pane item implements getTitle() but not getPath()", ->
|
||||
it "displays the title", ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
dummyView.getTitle = -> 'View Title'
|
||||
atom.workspace.getActivePane().activateItem(dummyView)
|
||||
expect(fileInfo.currentPath.textContent).toBe 'View Title'
|
||||
expect(fileInfo.currentPath).toBeVisible()
|
||||
|
||||
describe "when the active pane item neither getTitle() nor getPath()", ->
|
||||
it "hides the path view", ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
atom.workspace.getActivePane().activateItem(dummyView)
|
||||
expect(fileInfo.currentPath).toBeHidden()
|
||||
|
||||
describe "when the active pane item's title changes", ->
|
||||
it "updates the path view with the new title", ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
callbacks = []
|
||||
dummyView.onDidChangeTitle = (fn) ->
|
||||
callbacks.push(fn)
|
||||
{
|
||||
dispose: ->
|
||||
}
|
||||
dummyView.getTitle = -> 'View Title'
|
||||
atom.workspace.getActivePane().activateItem(dummyView)
|
||||
expect(fileInfo.currentPath.textContent).toBe 'View Title'
|
||||
dummyView.getTitle = -> 'New Title'
|
||||
callback() for callback in callbacks
|
||||
expect(fileInfo.currentPath.textContent).toBe 'New Title'
|
||||
|
||||
describe 'the cursor position tile', ->
|
||||
beforeEach ->
|
||||
atom.config.set('status-bar.cursorPositionFormat', 'foo %L bar %C')
|
||||
|
||||
it 'respects a format string', ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
editor.setCursorScreenPosition([1, 2])
|
||||
atom.views.performDocumentUpdate()
|
||||
expect(cursorPosition.textContent).toBe 'foo 2 bar 3'
|
||||
|
||||
it 'updates when the configuration changes', ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
editor.setCursorScreenPosition([1, 2])
|
||||
atom.views.performDocumentUpdate()
|
||||
expect(cursorPosition.textContent).toBe 'foo 2 bar 3'
|
||||
|
||||
atom.config.set('status-bar.cursorPositionFormat', 'baz %C quux %L')
|
||||
atom.views.performDocumentUpdate()
|
||||
expect(cursorPosition.textContent).toBe 'baz 3 quux 2'
|
||||
|
||||
describe "when clicked", ->
|
||||
it "triggers the go-to-line toggle event", ->
|
||||
eventHandler = jasmine.createSpy('eventHandler')
|
||||
atom.commands.add('atom-text-editor', 'go-to-line:toggle', eventHandler)
|
||||
cursorPosition.click()
|
||||
expect(eventHandler).toHaveBeenCalled()
|
||||
|
||||
describe 'the selection count tile', ->
|
||||
beforeEach ->
|
||||
atom.config.set('status-bar.selectionCountFormat', '%L foo %C bar selected')
|
||||
|
||||
it 'respects a format string', ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
editor.setSelectedBufferRange([[0, 0], [1, 30]])
|
||||
atom.views.performDocumentUpdate()
|
||||
expect(selectionCount.textContent).toBe "2 foo 60 bar selected"
|
||||
|
||||
it 'updates when the configuration changes', ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
editor.setSelectedBufferRange([[0, 0], [1, 30]])
|
||||
atom.views.performDocumentUpdate()
|
||||
expect(selectionCount.textContent).toBe "2 foo 60 bar selected"
|
||||
|
||||
atom.config.set('status-bar.selectionCountFormat', 'Selection: baz %C quux %L')
|
||||
atom.views.performDocumentUpdate()
|
||||
expect(selectionCount.textContent).toBe "Selection: baz 60 quux 2"
|
||||
|
||||
it 'does not include the next line if the last selected character is a LF', ->
|
||||
lineEndingRegExp = /\r\n|\n|\r/g
|
||||
buffer = editor.getBuffer()
|
||||
buffer.setText(buffer.getText().replace(lineEndingRegExp, '\n'))
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
editor.setSelectedBufferRange([[0, 0], [1, 0]])
|
||||
atom.views.performDocumentUpdate()
|
||||
expect(selectionCount.textContent).toBe "1 foo 30 bar selected"
|
||||
|
||||
it 'does not include the next line if the last selected character is CRLF', ->
|
||||
lineEndingRegExp = /\r\n|\n|\r/g
|
||||
buffer = editor.getBuffer()
|
||||
buffer.setText(buffer.getText().replace(lineEndingRegExp, '\r\n'))
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
editor.setSelectedBufferRange([[0, 0], [1, 0]])
|
||||
atom.views.performDocumentUpdate()
|
||||
expect(selectionCount.textContent).toBe "1 foo 31 bar selected"
|
||||
|
||||
describe "the git tile", ->
|
||||
gitView = null
|
||||
|
||||
hover = (element, fn) ->
|
||||
# FIXME: Only use hoverDefaults once Atom 1.13 is on stable
|
||||
hoverDelay = atom.tooltips.defaults.delay?.show ? atom.tooltips.hoverDefaults.delay.show
|
||||
element.dispatchEvent(new CustomEvent('mouseenter', bubbles: false))
|
||||
element.dispatchEvent(new CustomEvent('mouseover', bubbles: true))
|
||||
advanceClock(hoverDelay)
|
||||
fn()
|
||||
element.dispatchEvent(new CustomEvent('mouseleave', bubbles: false))
|
||||
element.dispatchEvent(new CustomEvent('mouseout', bubbles: true))
|
||||
advanceClock(hoverDelay)
|
||||
|
||||
setupWorkingDir = (name) ->
|
||||
dir = atom.project.getDirectories()[0]
|
||||
target = "#{os.tmpdir()}/#{name}"
|
||||
targetGit = target + '/.git'
|
||||
fs.copySync(dir.resolve('git/working-dir'), path.resolve(target))
|
||||
fs.removeSync(path.resolve(targetGit))
|
||||
fs.copySync(dir.resolve("git/#{name}.git"), path.resolve(targetGit))
|
||||
target
|
||||
|
||||
beforeEach ->
|
||||
[gitView] = statusBar.getRightTiles().map (tile) -> tile.getItem()
|
||||
|
||||
describe "the git ahead/behind count labels", ->
|
||||
beforeEach ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
|
||||
it "shows the number of commits that can be pushed/pulled", ->
|
||||
workingDir = setupWorkingDir('ahead-behind-repo')
|
||||
atom.project.setPaths([workingDir])
|
||||
filePath = atom.project.getDirectories()[0].resolve('a.txt')
|
||||
repo = atom.project.getRepositories()[0]
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath)
|
||||
.then -> repo.refreshStatus()
|
||||
|
||||
runs ->
|
||||
behindElement = document.body.querySelector(".commits-behind-label")
|
||||
aheadElement = document.body.querySelector(".commits-ahead-label")
|
||||
expect(aheadElement).toBeVisible()
|
||||
expect(behindElement).toBeVisible()
|
||||
expect(aheadElement.textContent).toContain '1'
|
||||
|
||||
it "stays hidden when no commits can be pushed/pulled", ->
|
||||
workingDir = setupWorkingDir('no-ahead-behind-repo')
|
||||
atom.project.setPaths([workingDir])
|
||||
filePath = atom.project.getDirectories()[0].resolve('a.txt')
|
||||
repo = atom.project.getRepositories()[0]
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath)
|
||||
.then -> repo.refreshStatus()
|
||||
|
||||
runs ->
|
||||
behindElement = document.body.querySelector(".commits-behind-label")
|
||||
aheadElement = document.body.querySelector(".commits-ahead-label")
|
||||
expect(aheadElement).not.toBeVisible()
|
||||
expect(behindElement).not.toBeVisible()
|
||||
|
||||
describe "the git branch label", ->
|
||||
projectPath = null
|
||||
beforeEach ->
|
||||
projectPath = atom.project.getDirectories()[0].resolve('git/working-dir')
|
||||
fs.moveSync(path.join(projectPath, 'git.git'), path.join(projectPath, '.git'))
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
|
||||
afterEach ->
|
||||
fs.moveSync(path.join(projectPath, '.git'), path.join(projectPath, 'git.git'))
|
||||
|
||||
it "displays the current branch for files in repositories", ->
|
||||
atom.project.setPaths([projectPath])
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('a.txt')
|
||||
|
||||
runs ->
|
||||
currentBranch = atom.project.getRepositories()[0].getShortHead()
|
||||
expect(gitView.branchArea).toBeVisible()
|
||||
expect(gitView.branchLabel.textContent).toBe currentBranch
|
||||
|
||||
atom.workspace.getActivePane().destroyItems()
|
||||
expect(gitView.branchArea).toBeVisible()
|
||||
expect(gitView.branchLabel.textContent).toBe currentBranch
|
||||
|
||||
atom.workspace.getActivePane().activateItem(dummyView)
|
||||
|
||||
runs -> expect(gitView.branchArea).not.toBeVisible()
|
||||
|
||||
it "displays the current branch tooltip", ->
|
||||
atom.project.setPaths([projectPath])
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('a.txt')
|
||||
|
||||
runs ->
|
||||
currentBranch = atom.project.getRepositories()[0].getShortHead()
|
||||
hover gitView.branchArea, ->
|
||||
expect(document.body.querySelector(".tooltip").innerText)
|
||||
.toBe("On branch #{currentBranch}")
|
||||
|
||||
it "doesn't display the current branch for a file not in a repository", ->
|
||||
atom.project.setPaths([os.tmpdir()])
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(path.join(os.tmpdir(), 'temp.txt'))
|
||||
|
||||
runs ->
|
||||
expect(gitView.branchArea).toBeHidden()
|
||||
|
||||
it "doesn't display the current branch for a file outside the current project", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(path.join(os.tmpdir(), 'atom-specs', 'not-in-project.txt'))
|
||||
|
||||
runs ->
|
||||
expect(gitView.branchArea).toBeHidden()
|
||||
|
||||
describe "the git status label", ->
|
||||
[repo, filePath, originalPathText, newPath, ignorePath, ignoredPath, projectPath] = []
|
||||
|
||||
beforeEach ->
|
||||
projectPath = atom.project.getDirectories()[0].resolve('git/working-dir')
|
||||
fs.moveSync(path.join(projectPath, 'git.git'), path.join(projectPath, '.git'))
|
||||
atom.project.setPaths([projectPath])
|
||||
filePath = atom.project.getDirectories()[0].resolve('a.txt')
|
||||
newPath = atom.project.getDirectories()[0].resolve('new.txt')
|
||||
fs.writeFileSync(newPath, "I'm new here")
|
||||
ignorePath = path.join(projectPath, '.gitignore')
|
||||
fs.writeFileSync(ignorePath, 'ignored.txt')
|
||||
ignoredPath = path.join(projectPath, 'ignored.txt')
|
||||
fs.writeFileSync(ignoredPath, '')
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
|
||||
repo = atom.project.getRepositories()[0]
|
||||
originalPathText = fs.readFileSync(filePath, 'utf8')
|
||||
waitsForPromise -> repo.refreshStatus()
|
||||
|
||||
afterEach ->
|
||||
fs.writeFileSync(filePath, originalPathText)
|
||||
fs.removeSync(newPath)
|
||||
fs.removeSync(ignorePath)
|
||||
fs.removeSync(ignoredPath)
|
||||
fs.moveSync(path.join(projectPath, '.git'), path.join(projectPath, 'git.git'))
|
||||
|
||||
it "displays the modified icon for a changed file", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath)
|
||||
.then ->
|
||||
fs.writeFileSync(filePath, "i've changed for the worse")
|
||||
repo.refreshStatus()
|
||||
runs ->
|
||||
expect(gitView.gitStatusIcon).toHaveClass('icon-diff-modified')
|
||||
|
||||
it "displays the 1 line added and not committed tooltip", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath)
|
||||
.then ->
|
||||
fs.writeFileSync(filePath, "i've changed for the worse")
|
||||
repo.refreshStatus()
|
||||
|
||||
runs ->
|
||||
hover gitView.gitStatusIcon, ->
|
||||
expect(document.body.querySelector(".tooltip").innerText)
|
||||
.toBe("1 line added to this file not yet committed")
|
||||
|
||||
it "displays the x lines added and not committed tooltip", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath)
|
||||
.then ->
|
||||
fs.writeFileSync(filePath, "i've changed#{os.EOL}for the worse")
|
||||
repo.refreshStatus()
|
||||
|
||||
runs ->
|
||||
hover gitView.gitStatusIcon, ->
|
||||
expect(document.body.querySelector(".tooltip").innerText)
|
||||
.toBe("2 lines added to this file not yet committed")
|
||||
|
||||
it "doesn't display the modified icon for an unchanged file", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath)
|
||||
.then -> repo.refreshStatus()
|
||||
|
||||
runs ->
|
||||
expect(gitView.gitStatusIcon).toHaveText('')
|
||||
|
||||
it "displays the new icon for a new file", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(newPath)
|
||||
.then -> repo.refreshStatus()
|
||||
|
||||
runs ->
|
||||
expect(gitView.gitStatusIcon).toHaveClass('icon-diff-added')
|
||||
hover gitView.gitStatusIcon, ->
|
||||
expect(document.body.querySelector(".tooltip").innerText)
|
||||
.toBe("1 line in this new file not yet committed")
|
||||
|
||||
it "displays the 1 line added and not committed to new file tooltip", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(newPath)
|
||||
.then -> repo.refreshStatus()
|
||||
|
||||
runs ->
|
||||
hover gitView.gitStatusIcon, ->
|
||||
expect(document.body.querySelector(".tooltip").innerText)
|
||||
.toBe("1 line in this new file not yet committed")
|
||||
|
||||
it "displays the x lines added and not committed to new file tooltip", ->
|
||||
fs.writeFileSync(newPath, "I'm new#{os.EOL}here")
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(newPath)
|
||||
.then -> repo.refreshStatus()
|
||||
|
||||
runs ->
|
||||
hover gitView.gitStatusIcon, ->
|
||||
expect(document.body.querySelector(".tooltip").innerText)
|
||||
.toBe("2 lines in this new file not yet committed")
|
||||
|
||||
it "displays the ignored icon for an ignored file", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(ignoredPath)
|
||||
|
||||
runs ->
|
||||
expect(gitView.gitStatusIcon).toHaveClass('icon-diff-ignored')
|
||||
hover gitView.gitStatusIcon, ->
|
||||
expect(document.body.querySelector(".tooltip").innerText)
|
||||
.toBe("File is ignored by git")
|
||||
|
||||
it "updates when a status-changed event occurs", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath)
|
||||
.then ->
|
||||
fs.writeFileSync(filePath, "i've changed for the worse")
|
||||
repo.refreshStatus()
|
||||
runs ->
|
||||
expect(gitView.gitStatusIcon).toHaveClass('icon-diff-modified')
|
||||
|
||||
waitsForPromise ->
|
||||
fs.writeFileSync(filePath, originalPathText)
|
||||
repo.refreshStatus()
|
||||
runs ->
|
||||
expect(gitView.gitStatusIcon).not.toHaveClass('icon-diff-modified')
|
||||
|
||||
it "displays the diff stat for modified files", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath)
|
||||
.then ->
|
||||
fs.writeFileSync(filePath, "i've changed for the worse")
|
||||
repo.refreshStatus()
|
||||
runs ->
|
||||
expect(gitView.gitStatusIcon).toHaveText('+1')
|
||||
|
||||
it "displays the diff stat for new files", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(newPath)
|
||||
.then -> repo.refreshStatus()
|
||||
|
||||
runs ->
|
||||
expect(gitView.gitStatusIcon).toHaveText('+1')
|
||||
|
||||
it "does not display for files not in the current project", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('/tmp/atom-specs/not-in-project.txt')
|
||||
|
||||
runs ->
|
||||
expect(gitView.gitStatusIcon).toBeHidden()
|
1
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/FETCH_HEAD
vendored
Normal file
1
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/FETCH_HEAD
vendored
Normal file
@ -0,0 +1 @@
|
||||
91c6b2a0a2c0d77bb9ce169154ef4263a3afc96c branch 'master' of https://github.com/as-cii/foo
|
1
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/HEAD
vendored
Normal file
1
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/HEAD
vendored
Normal file
@ -0,0 +1 @@
|
||||
ref: refs/heads/master
|
1
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/ORIG_HEAD
vendored
Normal file
1
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/ORIG_HEAD
vendored
Normal file
@ -0,0 +1 @@
|
||||
f97fc7338640a493675f375ed2eeaa2451715415
|
13
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/config
vendored
Normal file
13
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/config
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
logallrefupdates = true
|
||||
ignorecase = true
|
||||
precomposeunicode = true
|
||||
[remote "origin"]
|
||||
url = https://github.com/as-cii/foo
|
||||
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||
[branch "master"]
|
||||
remote = origin
|
||||
merge = refs/heads/master
|
BIN
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/index
vendored
Normal file
BIN
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/index
vendored
Normal file
Binary file not shown.
2
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/info/refs
vendored
Normal file
2
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/info/refs
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
60a497d3152925c000950e9cd2a874e8314c3155 refs/heads/master
|
||||
91c6b2a0a2c0d77bb9ce169154ef4263a3afc96c refs/remotes/origin/master
|
2
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/objects/info/packs
vendored
Normal file
2
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/objects/info/packs
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
P pack-ce64fd1ffdacf4364f6162466c9c8df5bca62c8b.pack
|
||||
|
Binary file not shown.
Binary file not shown.
3
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/packed-refs
vendored
Normal file
3
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/packed-refs
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# pack-refs with: peeled fully-peeled
|
||||
60a497d3152925c000950e9cd2a874e8314c3155 refs/heads/master
|
||||
91c6b2a0a2c0d77bb9ce169154ef4263a3afc96c refs/remotes/origin/master
|
1
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/refs/heads/master
vendored
Normal file
1
packages/status-bar/spec/fixtures/git/ahead-behind-repo.git/refs/heads/master
vendored
Normal file
@ -0,0 +1 @@
|
||||
60a497d3152925c000950e9cd2a874e8314c3155
|
1
packages/status-bar/spec/fixtures/git/master.git/HEAD
vendored
Normal file
1
packages/status-bar/spec/fixtures/git/master.git/HEAD
vendored
Normal file
@ -0,0 +1 @@
|
||||
ref: refs/heads/master
|
6
packages/status-bar/spec/fixtures/git/master.git/config
vendored
Normal file
6
packages/status-bar/spec/fixtures/git/master.git/config
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
logallrefupdates = true
|
||||
ignorecase = true
|
BIN
packages/status-bar/spec/fixtures/git/master.git/index
vendored
Normal file
BIN
packages/status-bar/spec/fixtures/git/master.git/index
vendored
Normal file
Binary file not shown.
BIN
packages/status-bar/spec/fixtures/git/master.git/objects/65/a457425a679cbe9adf0d2741785d3ceabb44a7
vendored
Normal file
BIN
packages/status-bar/spec/fixtures/git/master.git/objects/65/a457425a679cbe9adf0d2741785d3ceabb44a7
vendored
Normal file
Binary file not shown.
BIN
packages/status-bar/spec/fixtures/git/master.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
vendored
Normal file
BIN
packages/status-bar/spec/fixtures/git/master.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
vendored
Normal file
Binary file not shown.
BIN
packages/status-bar/spec/fixtures/git/master.git/objects/ef/046e9eecaa5255ea5e9817132d4001724d6ae1
vendored
Normal file
BIN
packages/status-bar/spec/fixtures/git/master.git/objects/ef/046e9eecaa5255ea5e9817132d4001724d6ae1
vendored
Normal file
Binary file not shown.
1
packages/status-bar/spec/fixtures/git/master.git/refs/heads/master
vendored
Normal file
1
packages/status-bar/spec/fixtures/git/master.git/refs/heads/master
vendored
Normal file
@ -0,0 +1 @@
|
||||
ef046e9eecaa5255ea5e9817132d4001724d6ae1
|
1
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/COMMIT_EDITMSG
vendored
Normal file
1
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/COMMIT_EDITMSG
vendored
Normal file
@ -0,0 +1 @@
|
||||
Initial Commit
|
1
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/HEAD
vendored
Normal file
1
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/HEAD
vendored
Normal file
@ -0,0 +1 @@
|
||||
ref: refs/heads/master
|
1
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/ORIG_HEAD
vendored
Normal file
1
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/ORIG_HEAD
vendored
Normal file
@ -0,0 +1 @@
|
||||
7189962af8559c6396aaad5758a2b0129c155529
|
14
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/config
vendored
Normal file
14
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/config
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
logallrefupdates = true
|
||||
ignorecase = true
|
||||
precomposeunicode = true
|
||||
[branch "master"]
|
||||
[remote "origin"]
|
||||
url = https://github.com/as-cii/foo
|
||||
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||
[branch "master"]
|
||||
remote = origin
|
||||
merge = refs/heads/master
|
1
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/description
vendored
Normal file
1
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/description
vendored
Normal file
@ -0,0 +1 @@
|
||||
Unnamed repository; edit this file 'description' to name the repository.
|
BIN
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/index
vendored
Normal file
BIN
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/index
vendored
Normal file
Binary file not shown.
2
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/info/refs
vendored
Normal file
2
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/info/refs
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
7189962af8559c6396aaad5758a2b0129c155529 refs/heads/master
|
||||
7189962af8559c6396aaad5758a2b0129c155529 refs/remotes/origin/master
|
2
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/objects/info/packs
vendored
Normal file
2
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/objects/info/packs
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
P pack-483aa6a931fd8d7256b902401f1b991daedfe0a5.pack
|
||||
|
Binary file not shown.
Binary file not shown.
3
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/packed-refs
vendored
Normal file
3
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/packed-refs
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# pack-refs with: peeled fully-peeled
|
||||
7189962af8559c6396aaad5758a2b0129c155529 refs/heads/master
|
||||
7189962af8559c6396aaad5758a2b0129c155529 refs/remotes/origin/master
|
1
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/refs/heads/master
vendored
Normal file
1
packages/status-bar/spec/fixtures/git/no-ahead-behind-repo.git/refs/heads/master
vendored
Normal file
@ -0,0 +1 @@
|
||||
7189962af8559c6396aaad5758a2b0129c155529
|
0
packages/status-bar/spec/fixtures/git/working-dir/a.txt
vendored
Normal file
0
packages/status-bar/spec/fixtures/git/working-dir/a.txt
vendored
Normal file
1
packages/status-bar/spec/fixtures/git/working-dir/file.txt
vendored
Normal file
1
packages/status-bar/spec/fixtures/git/working-dir/file.txt
vendored
Normal file
@ -0,0 +1 @@
|
||||
undefined
|
1
packages/status-bar/spec/fixtures/git/working-dir/git.git/HEAD
vendored
Normal file
1
packages/status-bar/spec/fixtures/git/working-dir/git.git/HEAD
vendored
Normal file
@ -0,0 +1 @@
|
||||
ref: refs/heads/master
|
6
packages/status-bar/spec/fixtures/git/working-dir/git.git/config
vendored
Normal file
6
packages/status-bar/spec/fixtures/git/working-dir/git.git/config
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
logallrefupdates = true
|
||||
ignorecase = true
|
BIN
packages/status-bar/spec/fixtures/git/working-dir/git.git/index
vendored
Normal file
BIN
packages/status-bar/spec/fixtures/git/working-dir/git.git/index
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
packages/status-bar/spec/fixtures/git/working-dir/git.git/refs/heads/master
vendored
Normal file
1
packages/status-bar/spec/fixtures/git/working-dir/git.git/refs/heads/master
vendored
Normal file
@ -0,0 +1 @@
|
||||
ef046e9eecaa5255ea5e9817132d4001724d6ae1
|
1
packages/status-bar/spec/fixtures/git/working-dir/other.txt
vendored
Normal file
1
packages/status-bar/spec/fixtures/git/working-dir/other.txt
vendored
Normal file
@ -0,0 +1 @@
|
||||
Full of text
|
13
packages/status-bar/spec/fixtures/sample.js
vendored
Normal file
13
packages/status-bar/spec/fixtures/sample.js
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
var quicksort = function () {
|
||||
var sort = function(items) {
|
||||
if (items.length <= 1) return items;
|
||||
var pivot = items.shift(), current, left = [], right = [];
|
||||
while(items.length > 0) {
|
||||
current = items.shift();
|
||||
current < pivot ? left.push(current) : right.push(current);
|
||||
}
|
||||
return sort(left).concat(pivot).concat(sort(right));
|
||||
};
|
||||
|
||||
return sort(Array.apply(this, arguments));
|
||||
};
|
1
packages/status-bar/spec/fixtures/sample.txt
vendored
Normal file
1
packages/status-bar/spec/fixtures/sample.txt
vendored
Normal file
@ -0,0 +1 @@
|
||||
Some text.
|
111
packages/status-bar/spec/status-bar-spec.coffee
Normal file
111
packages/status-bar/spec/status-bar-spec.coffee
Normal file
@ -0,0 +1,111 @@
|
||||
describe "Status Bar package", ->
|
||||
[editor, statusBar, statusBarService, workspaceElement, mainModule] = []
|
||||
|
||||
beforeEach ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('status-bar').then (pack) ->
|
||||
statusBar = workspaceElement.querySelector("status-bar")
|
||||
statusBarService = pack.mainModule.provideStatusBar()
|
||||
{mainModule} = pack
|
||||
|
||||
describe "@activate()", ->
|
||||
it "appends only one status bar", ->
|
||||
expect(workspaceElement.querySelectorAll('status-bar').length).toBe 1
|
||||
atom.workspace.getActivePane().splitRight(copyActiveItem: true)
|
||||
expect(workspaceElement.querySelectorAll('status-bar').length).toBe 1
|
||||
|
||||
describe "@deactivate()", ->
|
||||
it "removes the status bar view", ->
|
||||
waitsForPromise ->
|
||||
Promise.resolve(atom.packages.deactivatePackage('status-bar')) # Wrapped so works with Promise & non-Promise deactivate
|
||||
runs ->
|
||||
expect(workspaceElement.querySelector('status-bar')).toBeNull()
|
||||
|
||||
describe "isVisible option", ->
|
||||
beforeEach ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
|
||||
describe "when it is true", ->
|
||||
beforeEach ->
|
||||
atom.config.set 'status-bar.isVisible', true
|
||||
|
||||
it "shows status bar", ->
|
||||
expect(workspaceElement.querySelector('status-bar').parentNode).toBeVisible()
|
||||
|
||||
describe "when it is false", ->
|
||||
beforeEach ->
|
||||
atom.config.set 'status-bar.isVisible', false
|
||||
|
||||
it "hides status bar", ->
|
||||
expect(workspaceElement.querySelector('status-bar').parentNode).not.toBeVisible()
|
||||
|
||||
describe "when status-bar:toggle is triggered", ->
|
||||
beforeEach ->
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
atom.config.set 'status-bar.isVisible', true
|
||||
|
||||
it "hides or shows the status bar", ->
|
||||
atom.commands.dispatch(workspaceElement, 'status-bar:toggle')
|
||||
expect(workspaceElement.querySelector('status-bar').parentNode).not.toBeVisible()
|
||||
atom.commands.dispatch(workspaceElement, 'status-bar:toggle')
|
||||
expect(workspaceElement.querySelector('status-bar').parentNode).toBeVisible()
|
||||
|
||||
it "toggles the value of isVisible in config file", ->
|
||||
expect(atom.config.get 'status-bar.isVisible').toBe true
|
||||
atom.commands.dispatch(workspaceElement, 'status-bar:toggle')
|
||||
expect(atom.config.get 'status-bar.isVisible').toBe false
|
||||
atom.commands.dispatch(workspaceElement, 'status-bar:toggle')
|
||||
expect(atom.config.get 'status-bar.isVisible').toBe true
|
||||
|
||||
describe "full-width setting", ->
|
||||
[containers] = []
|
||||
|
||||
beforeEach ->
|
||||
containers = atom.workspace.panelContainers
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js')
|
||||
|
||||
it "expects the setting to be enabled by default", ->
|
||||
expect(atom.config.get('status-bar.fullWidth')).toBeTruthy()
|
||||
expect(containers.footer.panels).toContain(mainModule.statusBarPanel)
|
||||
|
||||
describe "when setting is changed", ->
|
||||
it "fits status bar to editor's width", ->
|
||||
atom.config.set('status-bar.fullWidth', false)
|
||||
expect(containers.bottom.panels).toContain(mainModule.statusBarPanel)
|
||||
expect(containers.footer.panels).not.toContain(mainModule.statusBarPanel)
|
||||
|
||||
it "restores the status-bar location when re-enabling setting", ->
|
||||
atom.config.set('status-bar.fullWidth', true)
|
||||
expect(containers.footer.panels).toContain(mainModule.statusBarPanel)
|
||||
expect(containers.bottom.panels).not.toContain(mainModule.statusBarPanel)
|
||||
|
||||
describe "the 'status-bar' service", ->
|
||||
it "allows tiles to be added, removed, and retrieved", ->
|
||||
dummyView = document.createElement("div")
|
||||
tile = statusBarService.addLeftTile(item: dummyView)
|
||||
expect(statusBar).toContain(dummyView)
|
||||
expect(statusBarService.getLeftTiles()).toContain(tile)
|
||||
tile.destroy()
|
||||
expect(statusBar).not.toContain(dummyView)
|
||||
expect(statusBarService.getLeftTiles()).not.toContain(tile)
|
||||
|
||||
dummyView = document.createElement("div")
|
||||
tile = statusBarService.addRightTile(item: dummyView)
|
||||
expect(statusBar).toContain(dummyView)
|
||||
expect(statusBarService.getRightTiles()).toContain(tile)
|
||||
tile.destroy()
|
||||
expect(statusBar).not.toContain(dummyView)
|
||||
expect(statusBarService.getRightTiles()).not.toContain(tile)
|
||||
|
||||
it "allows the git info tile to be disabled", ->
|
||||
getGitInfoTile = ->
|
||||
statusBar.getRightTiles().find((tile) -> tile.item.matches('.git-view'))
|
||||
|
||||
expect(getGitInfoTile()).not.toBeUndefined()
|
||||
statusBarService.disableGitInfoTile()
|
||||
expect(getGitInfoTile()).toBeUndefined()
|
103
packages/status-bar/spec/status-bar-view-spec.coffee
Normal file
103
packages/status-bar/spec/status-bar-view-spec.coffee
Normal file
@ -0,0 +1,103 @@
|
||||
StatusBarView = require '../lib/status-bar-view'
|
||||
|
||||
describe "StatusBarView", ->
|
||||
statusBarView = null
|
||||
|
||||
class TestItem
|
||||
constructor: (@id) ->
|
||||
|
||||
beforeEach ->
|
||||
statusBarView = new StatusBarView()
|
||||
|
||||
atom.views.addViewProvider TestItem, (model) ->
|
||||
element = document.createElement("item-view")
|
||||
element.model = model
|
||||
element
|
||||
|
||||
describe "::addLeftTile({item, priority})", ->
|
||||
it "appends the view for the given item to its left side", ->
|
||||
testItem1 = new TestItem(1)
|
||||
testItem2 = new TestItem(2)
|
||||
testItem3 = new TestItem(3)
|
||||
|
||||
tile1 = statusBarView.addLeftTile(item: testItem1, priority: 10)
|
||||
tile2 = statusBarView.addLeftTile(item: testItem2, priority: 30)
|
||||
tile3 = statusBarView.addLeftTile(item: testItem3, priority: 20)
|
||||
|
||||
{leftPanel} = statusBarView
|
||||
|
||||
expect(leftPanel.children[0].nodeName).toBe("ITEM-VIEW")
|
||||
expect(leftPanel.children[1].nodeName).toBe("ITEM-VIEW")
|
||||
expect(leftPanel.children[2].nodeName).toBe("ITEM-VIEW")
|
||||
|
||||
expect(leftPanel.children[0].model).toBe(testItem1)
|
||||
expect(leftPanel.children[1].model).toBe(testItem3)
|
||||
expect(leftPanel.children[2].model).toBe(testItem2)
|
||||
|
||||
expect(statusBarView.getLeftTiles()).toEqual([tile1, tile3, tile2])
|
||||
expect(tile1.getPriority()).toBe(10)
|
||||
expect(tile1.getItem()).toBe(testItem1)
|
||||
|
||||
it "allows the view to be removed", ->
|
||||
testItem = new TestItem(1)
|
||||
tile = statusBarView.addLeftTile(item: testItem, priority: 10)
|
||||
tile.destroy()
|
||||
expect(statusBarView.leftPanel.children.length).toBe(0)
|
||||
|
||||
statusBarView.addLeftTile(item: testItem, priority: 9)
|
||||
|
||||
describe "when no priority is given", ->
|
||||
it "appends the item", ->
|
||||
testItem1 = new TestItem(1)
|
||||
testItem2 = new TestItem(2)
|
||||
|
||||
statusBarView.addLeftTile(item: testItem1, priority: 1000)
|
||||
statusBarView.addLeftTile(item: testItem2)
|
||||
|
||||
{leftPanel} = statusBarView
|
||||
expect(leftPanel.children[0].model).toBe(testItem1)
|
||||
expect(leftPanel.children[1].model).toBe(testItem2)
|
||||
|
||||
describe "::addRightTile({item, priority})", ->
|
||||
it "appends the view for the given item to its right side", ->
|
||||
testItem1 = new TestItem(1)
|
||||
testItem2 = new TestItem(2)
|
||||
testItem3 = new TestItem(3)
|
||||
|
||||
tile1 = statusBarView.addRightTile(item: testItem1, priority: 10)
|
||||
tile2 = statusBarView.addRightTile(item: testItem2, priority: 30)
|
||||
tile3 = statusBarView.addRightTile(item: testItem3, priority: 20)
|
||||
|
||||
{rightPanel} = statusBarView
|
||||
|
||||
expect(rightPanel.children[0].nodeName).toBe("ITEM-VIEW")
|
||||
expect(rightPanel.children[1].nodeName).toBe("ITEM-VIEW")
|
||||
expect(rightPanel.children[2].nodeName).toBe("ITEM-VIEW")
|
||||
|
||||
expect(rightPanel.children[0].model).toBe(testItem2)
|
||||
expect(rightPanel.children[1].model).toBe(testItem3)
|
||||
expect(rightPanel.children[2].model).toBe(testItem1)
|
||||
|
||||
expect(statusBarView.getRightTiles()).toEqual([tile2, tile3, tile1])
|
||||
expect(tile1.getPriority()).toBe(10)
|
||||
expect(tile1.getItem()).toBe(testItem1)
|
||||
|
||||
it "allows the view to be removed", ->
|
||||
testItem = new TestItem(1)
|
||||
disposable = statusBarView.addRightTile(item: testItem, priority: 10)
|
||||
disposable.destroy()
|
||||
expect(statusBarView.rightPanel.children.length).toBe(0)
|
||||
|
||||
statusBarView.addRightTile(item: testItem, priority: 11)
|
||||
|
||||
describe "when no priority is given", ->
|
||||
it "prepends the item", ->
|
||||
testItem1 = new TestItem(1, priority: 1000)
|
||||
testItem2 = new TestItem(2)
|
||||
|
||||
statusBarView.addRightTile(item: testItem1, priority: 1000)
|
||||
statusBarView.addRightTile(item: testItem2)
|
||||
|
||||
{rightPanel} = statusBarView
|
||||
expect(rightPanel.children[0].model).toBe(testItem2)
|
||||
expect(rightPanel.children[1].model).toBe(testItem1)
|
114
packages/status-bar/styles/status-bar.less
Normal file
114
packages/status-bar/styles/status-bar.less
Normal file
@ -0,0 +1,114 @@
|
||||
@import "ui-variables";
|
||||
@import "octicon-mixins";
|
||||
|
||||
status-bar {
|
||||
display: block;
|
||||
font-size: 11px;
|
||||
line-height: @component-line-height - 3px;
|
||||
height: @component-line-height + 1px;
|
||||
position: relative;
|
||||
-webkit-user-select: none;
|
||||
cursor: default;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
min-width: -webkit-min-content;
|
||||
|
||||
a, a:hover {
|
||||
color: @text-color;
|
||||
}
|
||||
|
||||
.flexbox-repaint-hack {
|
||||
padding: 0 @component-line-height/2;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
// Use 1/3 of space -> will get cut-off first when narrow
|
||||
.status-bar-left {
|
||||
flex: 1 1 33%;
|
||||
}
|
||||
|
||||
// Use 2/3 of space
|
||||
.status-bar-right {
|
||||
padding-left: @component-padding;
|
||||
.inline-block {
|
||||
margin-right: 0;
|
||||
margin-left: @component-padding*1.5;
|
||||
& > .inline-block {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add horizontal overflow scrolling
|
||||
.status-bar-left,
|
||||
.status-bar-right {
|
||||
overflow-x: auto;
|
||||
// prevent badly behaved status bar items from causing vertical scrolling
|
||||
// in the status bar. They can always implement overflow: auto to scroll
|
||||
// within themselves.
|
||||
overflow-y: hidden;
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Limit inline-blocks from getting too long
|
||||
.inline-block {
|
||||
max-width: 20vw;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
// remove padding from buttons
|
||||
button.inline-block {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
// No width limit for file-info -> will get cut off if too long
|
||||
.inline-block.file-info {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.file-info.buffer-modified::after {
|
||||
content: '*';
|
||||
}
|
||||
|
||||
// All icons are smaller than normal (normal is 16px)
|
||||
.icon:before {
|
||||
.icon-size(14px);
|
||||
position: relative;
|
||||
top: 1px;
|
||||
width: auto; // Enable auto-width since not every icon has the same width
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.icon-diff-ignored:before,
|
||||
.commits-ahead-label:before,
|
||||
.commits-behind-label:before {
|
||||
margin-right: -1px;
|
||||
}
|
||||
|
||||
.hide,
|
||||
.current-path:empty,
|
||||
.cursor-position:empty,
|
||||
.selection-count:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.git-view {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.cursor-position a,
|
||||
.cursor-position a:hover {
|
||||
color: @text-color;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user