Atom/src/reopen-project-menu-manager.js

147 lines
4.5 KiB
JavaScript

const {CompositeDisposable} = require('event-kit')
const path = require('path')
module.exports =
class ReopenProjectMenuManager {
constructor ({menu, commands, history, config, open}) {
this.menuManager = menu
this.historyManager = history
this.config = config
this.open = open
this.projects = []
this.subscriptions = new CompositeDisposable()
this.subscriptions.add(
history.onDidChangeProjects(this.update.bind(this)),
config.onDidChange('core.reopenProjectMenuCount', ({oldValue, newValue}) => {
this.update()
}),
commands.add('atom-workspace', { 'application:reopen-project': this.reopenProjectCommand.bind(this) })
)
this.applyWindowsJumpListRemovals()
}
reopenProjectCommand (e) {
if (e.detail != null && e.detail.index != null) {
this.open(this.projects[e.detail.index].paths)
} else {
this.createReopenProjectListView()
}
}
createReopenProjectListView () {
if (this.reopenProjectListView == null) {
const ReopenProjectListView = require('./reopen-project-list-view')
this.reopenProjectListView = new ReopenProjectListView(paths => {
if (paths != null) {
this.open(paths)
}
})
}
this.reopenProjectListView.toggle()
}
update () {
this.disposeProjectMenu()
this.projects = this.historyManager.getProjects().slice(0, this.config.get('core.reopenProjectMenuCount'))
const newMenu = ReopenProjectMenuManager.createProjectsMenu(this.projects)
this.lastProjectMenu = this.menuManager.add([newMenu])
this.updateWindowsJumpList()
}
static taskDescription (paths) {
return paths.map(path => `${ReopenProjectMenuManager.betterBaseName(path)} (${path})`).join(' ')
}
// Windows users can right-click Atom taskbar and remove project from the jump list.
// We have to honor that or the group stops working. As we only get a partial list
// each time we remove them from history entirely.
async applyWindowsJumpListRemovals () {
if (process.platform !== 'win32') return
if (this.app === undefined) {
this.app = require('remote').app
}
const removed = this.app.getJumpListSettings().removedItems.map(i => i.description)
if (removed.length === 0) return
for (let project of this.historyManager.getProjects()) {
if (removed.includes(ReopenProjectMenuManager.taskDescription(project.paths))) {
await this.historyManager.removeProject(project.paths)
}
}
}
updateWindowsJumpList () {
if (process.platform !== 'win32') return
if (this.app === undefined) {
this.app = require('remote').app
}
this.app.setJumpList([
{
type: 'custom',
name: 'Recent Projects',
items: this.projects.map(project =>
({
type: 'task',
title: project.paths.map(ReopenProjectMenuManager.betterBaseName).join(', '),
description: ReopenProjectMenuManager.taskDescription(project.paths),
program: process.execPath,
args: project.paths.map(path => `"${path}"`).join(' '),
iconPath: path.join(path.dirname(process.execPath), 'resources', 'cli', 'folder.ico'),
iconIndex: 0
})
)
},
{ type: 'recent' },
{ items: [
{type: 'task', title: 'New Window', program: process.execPath, args: '--new-window', description: 'Opens a new Atom window'}
]}
])
}
dispose () {
this.subscriptions.dispose()
this.disposeProjectMenu()
if (this.reopenProjectListView != null) {
this.reopenProjectListView.dispose()
}
}
disposeProjectMenu () {
if (this.lastProjectMenu) {
this.lastProjectMenu.dispose()
this.lastProjectMenu = null
}
}
static createProjectsMenu (projects) {
return {
label: 'File',
submenu: [
{
label: 'Reopen Project',
submenu: projects.map((project, index) => ({
label: this.createLabel(project),
command: 'application:reopen-project',
commandDetail: {index: index}
}))
}
]
}
}
static createLabel (project) {
return project.paths.length === 1
? project.paths[0]
: project.paths.map(this.betterBaseName).join(', ')
}
static betterBaseName (directory) {
// Handles Windows roots better than path.basename which returns '' for 'd:' and 'd:\'
const match = directory.match(/^([a-z]:)[\\]?$/i)
return match ? match[1] + '\\' : path.basename(directory)
}
}