Skip to content

Commit

Permalink
Merge pull request atom#15834 from atom/jr-decaf-gutter-container
Browse files Browse the repository at this point in the history
Decaffeinate `GutterContainer`
  • Loading branch information
jasonrudolph authored Oct 7, 2017
2 parents 65efc99 + d546037 commit 7463925
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 151 deletions.
64 changes: 0 additions & 64 deletions spec/gutter-container-spec.coffee

This file was deleted.

77 changes: 77 additions & 0 deletions spec/gutter-container-spec.js
Original file line number Diff line number Diff line change
@@ -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([])
})
)
})
87 changes: 0 additions & 87 deletions src/gutter-container.coffee

This file was deleted.

108 changes: 108 additions & 0 deletions src/gutter-container.js
Original file line number Diff line number Diff line change
@@ -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)
}
}

0 comments on commit 7463925

Please sign in to comment.