-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request atom#15834 from atom/jr-decaf-gutter-container
Decaffeinate `GutterContainer`
- Loading branch information
Showing
4 changed files
with
185 additions
and
151 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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([]) | ||
}) | ||
) | ||
}) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} |