diff --git a/lib/buffer-view.coffee b/lib/buffer-view.coffee index f753ca4d..b1965c9e 100644 --- a/lib/buffer-view.coffee +++ b/lib/buffer-view.coffee @@ -3,6 +3,10 @@ FuzzyFinderView = require './fuzzy-finder-view' module.exports = class BufferView extends FuzzyFinderView + + initialize: (@closedBuffers) -> + super + toggle: -> if @panel?.isVisible() @cancel() @@ -19,11 +23,20 @@ class BufferView extends FuzzyFinderView populate: -> editors = atom.workspace.getTextEditors().filter (editor) -> editor.getPath()? activeEditor = atom.workspace.getActiveTextEditor() - editors = _.sortBy editors, (editor) -> - if editor is activeEditor - 0 - else - -(editor.lastOpened or 1) - - @paths = editors.map (editor) -> editor.getPath() - @setItems(_.uniq(@paths)) + + # Create a list of closed editors, matching the item data structure of editors list + closedEditors = _.map @closedBuffers.items, (dateClosed, path) -> + lastOpened: dateClosed + getPath: -> path + + @paths = _.chain(editors.concat(closedEditors)) + .sortBy (editor) -> + if editor is activeEditor + 0 + else + -(editor.lastOpened or 1) + .map (editor) -> editor.getPath() + .uniq() + .value() + + @setItems(@paths) diff --git a/lib/closed-buffers.coffee b/lib/closed-buffers.coffee new file mode 100644 index 00000000..237e01ac --- /dev/null +++ b/lib/closed-buffers.coffee @@ -0,0 +1,43 @@ +{CompositeDisposable} = require 'atom' +_ = require 'underscore-plus' + +module.exports = +class ClosedBuffers + constructor: -> + @items = {} + @disposables = new CompositeDisposable + + @disposables.add atom.workspace.onDidDestroyPaneItem ({item}) => + @ifItemHasPath item, (path, item) => + @addPath(path, item.lastOpened) + + @disposables.add atom.workspace.onDidOpen ({item}) => + @ifItemHasPath item, (path) => + @deletePath(path) + + @disposables.add atom.config.observe 'fuzzy-finder.maxClosedBuffersToRemember', (max) => + @limitPathsToRemember(max) + + ifItemHasPath: (item, fn) -> + path = item.getPath?() + if path + fn(path, item) + + addPath: (path, lastOpened) -> + limit = atom.config.get('fuzzy-finder.maxClosedBuffersToRemember') + if limit > 0 + @items[path] = Date.now() + @limitPathsToRemember(limit) + + deletePath: (path) -> + delete @items[path] + + limitPathsToRemember: (max) -> + keys = _.keys(@items) + overflow = keys.length - max + if overflow > 0 + _.times overflow, (i) => + @deletePath(keys[i]) + + dispose: -> + @disposables.dispose() diff --git a/lib/main.coffee b/lib/main.coffee index 66f3f5cc..1a74c404 100644 --- a/lib/main.coffee +++ b/lib/main.coffee @@ -1,3 +1,5 @@ +ClosedBuffers = require './closed-buffers' + module.exports = config: ignoredNames: @@ -10,9 +12,16 @@ module.exports = preserveLastSearch: type: 'boolean' default: false + maxClosedBuffersToRemember: + description: "The maximum count of closed buffers to show in the buffers list. Zero value means it's disabled" + type: 'number' + default: 0 + minimum: 0 + maximum: 100 activate: (state) -> @active = true + @closedBuffers = new ClosedBuffers() atom.commands.add 'atom-workspace', 'fuzzy-finder:toggle-file-finder': => @@ -41,6 +50,7 @@ module.exports = @gitStatusView.destroy() @gitStatusView = null @projectPaths = null + @closedBuffers.dispose() @stopLoadPathsTask() @active = false @@ -69,7 +79,7 @@ module.exports = createBufferView: -> unless @bufferView? BufferView = require './buffer-view' - @bufferView = new BufferView() + @bufferView = new BufferView(@closedBuffers) @bufferView startLoadPathsTask: -> diff --git a/spec/fuzzy-finder-spec.coffee b/spec/fuzzy-finder-spec.coffee index 365cd081..14641a29 100644 --- a/spec/fuzzy-finder-spec.coffee +++ b/spec/fuzzy-finder-spec.coffee @@ -331,6 +331,17 @@ describe 'FuzzyFinder', -> expect(_.pluck(bufferView.list.find('li > div.file'), 'outerText')).toEqual ['sample-with-tabs.coffee', 'sample.js', 'sample.txt'] expect(bufferView.list.children().first()).toHaveClass 'selected' + it 'do not list any closed buffers', -> + waitsForPromise -> + atom.workspace.open 'sample.html' + + runs -> + atom.workspace.getActivePane().destroyActiveItem() + dispatchCommand('toggle-buffer-finder') + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe true + expect(_.pluck(bufferView.list.find('li > div.file'), 'outerText')).toEqual ['sample.js', 'sample.txt'] + expect(bufferView.list.children().first()).toHaveClass 'selected' + it "serializes the list of paths and their last opened time", -> waitsForPromise -> atom.workspace.open 'sample-with-tabs.coffee' @@ -359,6 +370,52 @@ describe 'FuzzyFinder', -> expect(_.last bufferPath.split path.sep).toBe paths.shift() expect(time).toBeGreaterThan 50000 + describe 'when the maxClosedBuffersToRemember config is set to a non-zero value', -> + beforeEach -> + atom.config.set('fuzzy-finder.maxClosedBuffersToRemember', 3) + + describe 'when there are a bunch of buffers that have been closed', -> + beforeEach -> + # sample.js and sample.txt are already opened (from parent beforeEach) + # open a bunch of new files but close them immediately + waitsForPromise -> + atom.workspace.getActivePane().destroyActiveItem() + advanceClock(10) + atom.workspace.open 'sample-with-tabs.coffee' + waitsForPromise -> + atom.workspace.getActivePane().destroyActiveItem() + advanceClock(10) + atom.workspace.open 'a' + waitsForPromise -> + atom.workspace.getActivePane().destroyActiveItem() + advanceClock(10) + atom.workspace.open 'b' + waitsForPromise -> + atom.workspace.getActivePane().destroyActiveItem() + advanceClock(10) + atom.workspace.open 'sample.html' + + waitsForPromise -> + # re-open one of the closed buffer, new "current item" + atom.workspace.getActivePane().destroyActiveItem() + advanceClock(10) + atom.workspace.open 'sample.html' + + it 'lists the paths of the current items+closed buffers within max limit, sorted by most recently opened but with the current item last', -> + dispatchCommand('toggle-buffer-finder') + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe true + expect(_.pluck(bufferView.list.find('li > div.file'), 'outerText')).toEqual ['sample.js', 'b', 'a', 'sample.html'] + + describe 'when modifies the config setting', -> + beforeEach -> + atom.config.set('fuzzy-finder.maxClosedBuffersToRemember', 1) + + it 'limit the closed buffers list accordingly', -> + # should cut out 'a' and 'b' from above + dispatchCommand('toggle-buffer-finder') + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe true + expect(_.pluck(bufferView.list.find('li > div.file'), 'outerText')).toEqual ['sample.js', 'b', 'sample.html'] + describe "when there are only panes with anonymous items", -> it "does not open", -> atom.workspace.getActivePane().destroy()