Atom is a text editor hackable to its core. It allows you to modify and add functionality to better fit your needs.

Yeah, OK, but what does it mean to be a hackable editor?

Everything in Atom is a package and every feature comes in the form of a package. This makes it a highly modular text editor. It is so modular that anyone can write packages for it.

Atom has a bunch of people contributing to it on github, so don’t hesitate to lend a hand!

How to Install a Package?

There are two ways to install packages for Atom,

  1. Enter apm install package-name on your terminal. Obviously, the Atom package manager, apm, must be installed (you can enter apm to verify installation).
  2. Open Atom, go to edit > preferences > install and search for the package you wish to install.

Both of these methods will download your packages to the default directory (e.g., ~/.atom/packages on linux).

Package States

A package can be active, loaded, unloaded, or inactive. Internally, the PackageManager class (in package-manager.js) manages these states.

Loaded Packages

When a package is loaded it means that Atom knows it is installed and that it will be either activated or deactivated. First, Atom will get every available package by saving the required paths (i.e., folders containing the packages) in an array and use that to create another array containing the packages found on those directories. Loading a package causes Atom to read and parse the package's metadata and resources such as keymaps, menus, stylesheets, etc.

loadPackages () {
// Ensure atom exports is already in the require cache so the load time
// of the first package isn't skewed by being the first to require atom
require('../exports/atom')

const disabledPackageNames = new Set(this.config.get('core.disabledPackages'))
this.config.transact(() => {
for (const pack of this.getAvailablePackages()) {
this.loadAvailablePackage(pack, disabledPackageNames)
}
})
this.initialPackagesLoaded = true
this.emitter.emit('did-load-initial-packages')
}
 getAvailablePackages () {
const packages = []
const packagesByName = new Set()

for (const packageDirPath of this.packageDirPaths) {
if (fs.isDirectorySync(packageDirPath)) {
for (let packagePath of fs.readdirSync(packageDirPath)) {
packagePath = path.join(packageDirPath, packagePath)
const packageName = path.basename(packagePath)
if (!packageName.startsWith('.') && !packagesByName.has(packageName) && fs.isDirectorySync(packagePath)) {
packages.push({
name: packageName,
path: packagePath,
isBundled: false
})
packagesByName.add(packageName)
}
}
}
}

for (const packageName in this.packageDependencies) {
if (!packagesByName.has(packageName)) {
packages.push({
name: packageName,
path: path.join(this.resourcePath, 'node_modules', packageName),
isBundled: true
})
}
}

return packages.sort((a, b) => a.name.localeCompare(b.name))
}

Unloaded Packages

Unloading a package removes it completely from the PackageManager. Here Atom will look for that package in the loadedPackages list and remove it.

unloadPackages () {
_.keys(this.loadedPackages).forEach(name => this.unloadPackage(name))
}

unloadPackage (name) {
if (this.isPackageActive(name)) {
throw new Error(`Tried to unload active package '${name}'`)
}
const pack = this.getLoadedPackage(name)
if (pack) {
delete this.loadedPackages[pack.name]
this.emitter.emit('did-unload-package', pack)
} else {
throw new Error(`No loaded package for name '${name}'`)
}
}

Active Packages

When a package is activated the activate() method on the PackageManager is called. It gets every loaded package and tries to call activate() on the package's main module.

This function skips every package that was disabled by the user.

activatePackages (packages) {
const promises = []
this.config.transactAsync(() => {
for (const pack of packages) {
const promise = this.activatePackage(pack.name)
if (!pack.activationShouldBeDeferred()) {
promises.push(promise)
}
}
return Promise.all(promises)
})
this.observeDisabledPackages()
this.observePackagesWithKeymapsDisabled()
return promises
}

Inactive Packages

Deactivating a package unregisters the package's resources and calls deactivate() on the package's main module.

// Deactivate all packages
async deactivatePackages () {
await this.config.transactAsync(() =>
Promise.all(this.getLoadedPackages().map(pack => this.deactivatePackage(pack.name, true)))
)
this.unobserveDisabledPackages()
this.unobservePackagesWithKeymapsDisabled()
}

// Deactivate the package with the given name
async deactivatePackage (name, suppressSerialization) {
const pack = this.getLoadedPackage(name)
if (pack == null) {
return
}

if (!suppressSerialization && this.isPackageActive(pack.name)) {
this.serializePackage(pack)
}

const deactivationResult = pack.deactivate()
if (deactivationResult && typeof deactivationResult.then === 'function') {
await deactivationResult
}

delete this.activePackages[pack.name]
delete this.activatingPackages[pack.name]
this.emitter.emit('did-deactivate-package', pack)
}

Turns out Atom is constantly keeping an eye on its packages folder, and whenever it sees a change a callback is executed.

The PathWatcher class is defined in path-watcher.js and it is used to manage a subscription to file system events that occur beneath a root directory.

The flow works this way,

  • first you install a package by adding it to the packages folder,
  • the PathWatcher detects the change and returns the according callback,
  • then the PackageManager decides what to do with the new package.

Wish to Contribute?

As I mentioned before, everyone is welcomed to contribute! You can also create your own packages. I will not go into details about it here since they have done an amazing job at that already. Just head to their site and follow their tutorial on How to Hack Atom.

 

Learn More about Encora

We are the software development company fiercely committed and uniquely equipped to enable companies to do what they can’t do now.

Learn More

Global Delivery

READ MORE

Careers

READ MORE

Industries

READ MORE

Related Insights

Enabling Transformation in Hospitality through Technology-Led Innovation

As the exclusive sponsor of the 2024 Hotel Visionary Awards, we support organizations leading ...

Read More

Key Insights from HLTH 2024: The Future of Patient-Centered Healthcare

Discover key insights from HLTH 2024 on digital health, AI in diagnostics, data interoperability, ...

Read More

Data-Driven Engineering: Transforming Operations and Products from Insight to Impact

Discover how data-driven engineering transforms operations and product development, enhancing team ...

Read More
Previous Previous
Next

Accelerate Your Path
to Market Leadership 

Encora logo

Santa Clara, CA

+1 669-236-2674

letstalk@encora.com

Innovation Acceleration

Speak With an Expert

Encora logo

Santa Clara, CA

+1 (480) 991 3635

letstalk@encora.com

Innovation Acceleration