mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-19 23:17:16 +03:00
Merge pull request #15834 from atom/jr-decaf-gutter-container
Decaffeinate `GutterContainer`
This commit is contained in:
commit
7463925e94
@ -1,64 +0,0 @@
|
||||
Gutter = require '../src/gutter'
|
||||
GutterContainer = require '../src/gutter-container'
|
||||
|
||||
describe 'GutterContainer', ->
|
||||
gutterContainer = null
|
||||
fakeTextEditor = {
|
||||
scheduleComponentUpdate: ->
|
||||
}
|
||||
|
||||
beforeEach ->
|
||||
gutterContainer = new GutterContainer fakeTextEditor
|
||||
|
||||
describe 'when initialized', ->
|
||||
it 'it has no gutters', ->
|
||||
expect(gutterContainer.getGutters().length).toBe 0
|
||||
|
||||
describe '::addGutter', ->
|
||||
it 'creates a new gutter', ->
|
||||
newGutter = gutterContainer.addGutter {'test-gutter', priority: 1}
|
||||
expect(gutterContainer.getGutters()).toEqual [newGutter]
|
||||
expect(newGutter.priority).toBe 1
|
||||
|
||||
it 'throws an error if the provided gutter name is already in use', ->
|
||||
name = 'test-gutter'
|
||||
gutterContainer.addGutter {name}
|
||||
expect(gutterContainer.addGutter.bind(null, {name})).toThrow()
|
||||
|
||||
it 'keeps added gutters sorted by ascending priority', ->
|
||||
gutter1 = gutterContainer.addGutter {name: 'first', priority: 1}
|
||||
gutter3 = gutterContainer.addGutter {name: 'third', priority: 3}
|
||||
gutter2 = gutterContainer.addGutter {name: 'second', priority: 2}
|
||||
expect(gutterContainer.getGutters()).toEqual [gutter1, gutter2, gutter3]
|
||||
|
||||
describe '::removeGutter', ->
|
||||
removedGutters = null
|
||||
|
||||
beforeEach ->
|
||||
gutterContainer = new GutterContainer fakeTextEditor
|
||||
removedGutters = []
|
||||
gutterContainer.onDidRemoveGutter (gutterName) ->
|
||||
removedGutters.push gutterName
|
||||
|
||||
it 'removes the gutter if it is contained by this GutterContainer', ->
|
||||
gutter = gutterContainer.addGutter {'test-gutter'}
|
||||
expect(gutterContainer.getGutters()).toEqual [gutter]
|
||||
gutterContainer.removeGutter gutter
|
||||
expect(gutterContainer.getGutters().length).toBe 0
|
||||
expect(removedGutters).toEqual [gutter.name]
|
||||
|
||||
it 'throws an error if the gutter is not within this GutterContainer', ->
|
||||
fakeOtherTextEditor = {}
|
||||
otherGutterContainer = new GutterContainer fakeOtherTextEditor
|
||||
gutter = new Gutter 'gutter-name', otherGutterContainer
|
||||
expect(gutterContainer.removeGutter.bind(null, gutter)).toThrow()
|
||||
|
||||
describe '::destroy', ->
|
||||
it 'clears its array of gutters and destroys custom gutters', ->
|
||||
newGutter = gutterContainer.addGutter {'test-gutter', priority: 1}
|
||||
newGutterSpy = jasmine.createSpy()
|
||||
newGutter.onDidDestroy(newGutterSpy)
|
||||
|
||||
gutterContainer.destroy()
|
||||
expect(newGutterSpy).toHaveBeenCalled()
|
||||
expect(gutterContainer.getGutters()).toEqual []
|
77
spec/gutter-container-spec.js
Normal file
77
spec/gutter-container-spec.js
Normal file
@ -0,0 +1,77 @@
|
||||
const Gutter = require('../src/gutter')
|
||||
const GutterContainer = require('../src/gutter-container')
|
||||
|
||||
describe('GutterContainer', () => {
|
||||
let gutterContainer = null
|
||||
const fakeTextEditor = {
|
||||
scheduleComponentUpdate () {}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
gutterContainer = new GutterContainer(fakeTextEditor)
|
||||
})
|
||||
|
||||
describe('when initialized', () =>
|
||||
it('it has no gutters', () => {
|
||||
expect(gutterContainer.getGutters().length).toBe(0)
|
||||
})
|
||||
)
|
||||
|
||||
describe('::addGutter', () => {
|
||||
it('creates a new gutter', () => {
|
||||
const newGutter = gutterContainer.addGutter({'test-gutter': 'test-gutter', priority: 1})
|
||||
expect(gutterContainer.getGutters()).toEqual([newGutter])
|
||||
expect(newGutter.priority).toBe(1)
|
||||
})
|
||||
|
||||
it('throws an error if the provided gutter name is already in use', () => {
|
||||
const name = 'test-gutter'
|
||||
gutterContainer.addGutter({name})
|
||||
expect(gutterContainer.addGutter.bind(null, {name})).toThrow()
|
||||
})
|
||||
|
||||
it('keeps added gutters sorted by ascending priority', () => {
|
||||
const gutter1 = gutterContainer.addGutter({name: 'first', priority: 1})
|
||||
const gutter3 = gutterContainer.addGutter({name: 'third', priority: 3})
|
||||
const gutter2 = gutterContainer.addGutter({name: 'second', priority: 2})
|
||||
expect(gutterContainer.getGutters()).toEqual([gutter1, gutter2, gutter3])
|
||||
})
|
||||
})
|
||||
|
||||
describe('::removeGutter', () => {
|
||||
let removedGutters
|
||||
|
||||
beforeEach(function () {
|
||||
gutterContainer = new GutterContainer(fakeTextEditor)
|
||||
removedGutters = []
|
||||
gutterContainer.onDidRemoveGutter(gutterName => removedGutters.push(gutterName))
|
||||
})
|
||||
|
||||
it('removes the gutter if it is contained by this GutterContainer', () => {
|
||||
const gutter = gutterContainer.addGutter({'test-gutter': 'test-gutter'})
|
||||
expect(gutterContainer.getGutters()).toEqual([gutter])
|
||||
gutterContainer.removeGutter(gutter)
|
||||
expect(gutterContainer.getGutters().length).toBe(0)
|
||||
expect(removedGutters).toEqual([gutter.name])
|
||||
})
|
||||
|
||||
it('throws an error if the gutter is not within this GutterContainer', () => {
|
||||
const fakeOtherTextEditor = {}
|
||||
const otherGutterContainer = new GutterContainer(fakeOtherTextEditor)
|
||||
const gutter = new Gutter('gutter-name', otherGutterContainer)
|
||||
expect(gutterContainer.removeGutter.bind(null, gutter)).toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
describe('::destroy', () =>
|
||||
it('clears its array of gutters and destroys custom gutters', () => {
|
||||
const newGutter = gutterContainer.addGutter({'test-gutter': 'test-gutter', priority: 1})
|
||||
const newGutterSpy = jasmine.createSpy()
|
||||
newGutter.onDidDestroy(newGutterSpy)
|
||||
|
||||
gutterContainer.destroy()
|
||||
expect(newGutterSpy).toHaveBeenCalled()
|
||||
expect(gutterContainer.getGutters()).toEqual([])
|
||||
})
|
||||
)
|
||||
})
|
@ -1,87 +0,0 @@
|
||||
{Emitter} = require 'event-kit'
|
||||
Gutter = require './gutter'
|
||||
|
||||
module.exports =
|
||||
class GutterContainer
|
||||
constructor: (textEditor) ->
|
||||
@gutters = []
|
||||
@textEditor = textEditor
|
||||
@emitter = new Emitter
|
||||
|
||||
scheduleComponentUpdate: ->
|
||||
@textEditor.scheduleComponentUpdate()
|
||||
|
||||
destroy: ->
|
||||
# Create a copy, because `Gutter::destroy` removes the gutter from
|
||||
# GutterContainer's @gutters.
|
||||
guttersToDestroy = @gutters.slice(0)
|
||||
for gutter in guttersToDestroy
|
||||
gutter.destroy() if gutter.name isnt 'line-number'
|
||||
@gutters = []
|
||||
@emitter.dispose()
|
||||
|
||||
addGutter: (options) ->
|
||||
options = options ? {}
|
||||
gutterName = options.name
|
||||
if gutterName is null
|
||||
throw new Error('A name is required to create a gutter.')
|
||||
if @gutterWithName(gutterName)
|
||||
throw new Error('Tried to create a gutter with a name that is already in use.')
|
||||
newGutter = new Gutter(this, options)
|
||||
|
||||
inserted = false
|
||||
# Insert the gutter into the gutters array, sorted in ascending order by 'priority'.
|
||||
# This could be optimized, but there are unlikely to be many gutters.
|
||||
for i in [0...@gutters.length]
|
||||
if @gutters[i].priority >= newGutter.priority
|
||||
@gutters.splice(i, 0, newGutter)
|
||||
inserted = true
|
||||
break
|
||||
if not inserted
|
||||
@gutters.push newGutter
|
||||
@scheduleComponentUpdate()
|
||||
@emitter.emit 'did-add-gutter', newGutter
|
||||
return newGutter
|
||||
|
||||
getGutters: ->
|
||||
@gutters.slice()
|
||||
|
||||
gutterWithName: (name) ->
|
||||
for gutter in @gutters
|
||||
if gutter.name is name then return gutter
|
||||
null
|
||||
|
||||
observeGutters: (callback) ->
|
||||
callback(gutter) for gutter in @getGutters()
|
||||
@onDidAddGutter callback
|
||||
|
||||
onDidAddGutter: (callback) ->
|
||||
@emitter.on 'did-add-gutter', callback
|
||||
|
||||
onDidRemoveGutter: (callback) ->
|
||||
@emitter.on 'did-remove-gutter', callback
|
||||
|
||||
###
|
||||
Section: Private Methods
|
||||
###
|
||||
|
||||
# Processes the destruction of the gutter. Throws an error if this gutter is
|
||||
# not within this gutterContainer.
|
||||
removeGutter: (gutter) ->
|
||||
index = @gutters.indexOf(gutter)
|
||||
if index > -1
|
||||
@gutters.splice(index, 1)
|
||||
@scheduleComponentUpdate()
|
||||
@emitter.emit 'did-remove-gutter', gutter.name
|
||||
else
|
||||
throw new Error 'The given gutter cannot be removed because it is not ' +
|
||||
'within this GutterContainer.'
|
||||
|
||||
# The public interface is Gutter::decorateMarker or TextEditor::decorateMarker.
|
||||
addGutterDecoration: (gutter, marker, options) ->
|
||||
if gutter.name is 'line-number'
|
||||
options.type = 'line-number'
|
||||
else
|
||||
options.type = 'gutter'
|
||||
options.gutterName = gutter.name
|
||||
@textEditor.decorateMarker(marker, options)
|
108
src/gutter-container.js
Normal file
108
src/gutter-container.js
Normal file
@ -0,0 +1,108 @@
|
||||
const {Emitter} = require('event-kit')
|
||||
const Gutter = require('./gutter')
|
||||
|
||||
module.exports = class GutterContainer {
|
||||
constructor (textEditor) {
|
||||
this.gutters = []
|
||||
this.textEditor = textEditor
|
||||
this.emitter = new Emitter()
|
||||
}
|
||||
|
||||
scheduleComponentUpdate () {
|
||||
this.textEditor.scheduleComponentUpdate()
|
||||
}
|
||||
|
||||
destroy () {
|
||||
// Create a copy, because `Gutter::destroy` removes the gutter from
|
||||
// GutterContainer's @gutters.
|
||||
const guttersToDestroy = this.gutters.slice(0)
|
||||
for (let gutter of guttersToDestroy) {
|
||||
if (gutter.name !== 'line-number') { gutter.destroy() }
|
||||
}
|
||||
this.gutters = []
|
||||
this.emitter.dispose()
|
||||
}
|
||||
|
||||
addGutter (options) {
|
||||
options = options || {}
|
||||
const gutterName = options.name
|
||||
if (gutterName === null) {
|
||||
throw new Error('A name is required to create a gutter.')
|
||||
}
|
||||
if (this.gutterWithName(gutterName)) {
|
||||
throw new Error('Tried to create a gutter with a name that is already in use.')
|
||||
}
|
||||
const newGutter = new Gutter(this, options)
|
||||
|
||||
let inserted = false
|
||||
// Insert the gutter into the gutters array, sorted in ascending order by 'priority'.
|
||||
// This could be optimized, but there are unlikely to be many gutters.
|
||||
for (let i = 0; i < this.gutters.length; i++) {
|
||||
if (this.gutters[i].priority >= newGutter.priority) {
|
||||
this.gutters.splice(i, 0, newGutter)
|
||||
inserted = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!inserted) {
|
||||
this.gutters.push(newGutter)
|
||||
}
|
||||
this.scheduleComponentUpdate()
|
||||
this.emitter.emit('did-add-gutter', newGutter)
|
||||
return newGutter
|
||||
}
|
||||
|
||||
getGutters () {
|
||||
return this.gutters.slice()
|
||||
}
|
||||
|
||||
gutterWithName (name) {
|
||||
for (let gutter of this.gutters) {
|
||||
if (gutter.name === name) { return gutter }
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
observeGutters (callback) {
|
||||
for (let gutter of this.getGutters()) { callback(gutter) }
|
||||
return this.onDidAddGutter(callback)
|
||||
}
|
||||
|
||||
onDidAddGutter (callback) {
|
||||
return this.emitter.on('did-add-gutter', callback)
|
||||
}
|
||||
|
||||
onDidRemoveGutter (callback) {
|
||||
return this.emitter.on('did-remove-gutter', callback)
|
||||
}
|
||||
|
||||
/*
|
||||
Section: Private Methods
|
||||
*/
|
||||
|
||||
// Processes the destruction of the gutter. Throws an error if this gutter is
|
||||
// not within this gutterContainer.
|
||||
removeGutter (gutter) {
|
||||
const index = this.gutters.indexOf(gutter)
|
||||
if (index > -1) {
|
||||
this.gutters.splice(index, 1)
|
||||
this.scheduleComponentUpdate()
|
||||
this.emitter.emit('did-remove-gutter', gutter.name)
|
||||
} else {
|
||||
throw new Error('The given gutter cannot be removed because it is not ' +
|
||||
'within this GutterContainer.'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// The public interface is Gutter::decorateMarker or TextEditor::decorateMarker.
|
||||
addGutterDecoration (gutter, marker, options) {
|
||||
if (gutter.name === 'line-number') {
|
||||
options.type = 'line-number'
|
||||
} else {
|
||||
options.type = 'gutter'
|
||||
}
|
||||
options.gutterName = gutter.name
|
||||
return this.textEditor.decorateMarker(marker, options)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user