Hacking the hackable editor
Creating your first Atom plugin
What is this tutorial for?
Today, we will be creating our first atom plugin. We will be creating a plugin that implements the basic functionality of a dictionary lookup. It will allow a user to search a word directly in the editor, by either highlighting the word or placing the cursor somewhere in the word. You can follow this post along with the YouTube video here.
What is Atom?
Creating an Atom Plugin
To get started building your first Atom Plugin, you must have Atom installed. If you do not already have it, go grab it for free from their website: https://atom.io/
So, let’s get started with our first plugin!
Atom stores all it’s plugins within the atom folder,
.atom. It is located at
\Users\user-name\.atom. Within the folder, there is a subfolder called
packages. Which, as you may have guessed, is where all the packages can be found. Every package has its own folder.
The first step is to create a package for the plugin. I will create a folder called
Depending on the type of package you want to build, you may not require all these folders (or you may require additional ones). Nonetheless, this gives you a good breakdown of what a basic package structure looks in Atom:
Now let’s take a look at some of these folders and files.
For our package to be recognized by Atom, we need to add a .json file:
package.json. This json file will contain metadata about the package and is based off of the regular Node
package.json keys (https://docs.npmjs.com/files/package.json).
A general structure and important keys to implement are as follows:
nameis the name of the package
mainis the location of entry point to the plugin, kind of like main (usually located in the lib folder named as plugin-name.coffee.. and if the
mainkey is not in your
package.jsonfile, Atom will default to looking for an
versionis the version number of the package, and must follow the convention:
major.minor.bug(you should indicate
descriptioninforms others about what the package does
enginesindicates the minimal required version of Atom
dependenciesindicates other packages needed
repositoryis a URL indicating where the public repository is located
bugsis a URL where others can report issues
licenseindicates the license
Some other keys…
styles: an Array of Strings describing the order in which your style sheets need to be loaded (if not specified they will be loaded alphabetically)
keymaps: an Array of Strings i describing the order in which your key mappings need to be loaded (if not specified they will be loaded alphabetically)
menus: an Array of Strings describing the order in which your menu mappings eed to be loaded (if not specified they will be loaded alphabetically)
There are many other keys, however for now this is as much as we need to create our plugin.
Now that your package has a valid
package.json file, Atom can recognize it and load it. However, it’s totally useless right now. So, it’s time to make it useful by giving it some features!
Our package logic can be found at plugin-name.coffee/.js.
- your-plugin.coffee/your-plugin.js handles the logic of the plugin and can be viewed as the main package file
- your-plugin-view.coffee/.js handles the UI elements of the package
In your main, you usually have the following 3 methods:
deactivatemethod destroys the various class instances created
serializemethod passes on the serialization to the View class
activatemethod is what is executed when your plugin is loaded and instantiates the view class.
Here is an example skeleton for my-first-plugin.js:
Code explained: Commands are events triggered by a user and packages can subscribe to commands. By subscribing, they can execute code in response to the event (a.k.a the command) that was triggered by the user. When we want to subscribe to multiple events that’s where the CompositeDisposable class comes in handy, but we won’t get into any specifics right now.
toggle method is what gets called every time the user wants to run the package (‘toggles the package’). It is invoked either by the menu item or a hotkey.
Here is an example skeleton for my-first-plugin-view.js:
So let’s dive in. First, we want to grab the word we want to lookup.
We do this by creating an reference to the current state of the editor and finding the word that is either selected or where the user’s cursor is. We will add this snippet to our toggle method. Also, don’t forget to define the variable wordToSearch:
Next, we will add a method in our view to update itself.
In our view, the root element only had one child (index starts at 0) and we want to update it’s text to reflect the word we just grabbed from the editor. Afterwards, we will need to go back into our logic and add the following line:
With this line, we will call the setElement method we created which will update the element with our word.
At this point, you may notice that as you make changes to your package the changes aren’t reflected right away. You need to reload Atom, either by closing and re-opening or hitting View > Developer > Reload. This will ensure Atom runs the latest version of our source code.
Therefore, reload Atom and toggle the plugin. The panel now displays the word where the cursor is focused or highlighted.
Let’s take a moment to look at the flow of our package in Atom:
- First, Atom starts up.
- Second, Atom begins loading packages.
- When Atom reaches our plugin it reads the
- Atom is going to load in our keymaps, menus, styles and main
- At some point in time while the user is using Atom, uur package gets toggled
- Once our plugin is toggled, Atom executes the
activatemethod. The activate method sets up the UI by creating a hidden view and then executes
your-pluggin:togglewhich reveals the hidden view!
- Lastly, when toggle is called again Atom executes the toggle command again which hides the view.
Connecting to an API
Now, we will need to connect our plugin with some sort of Dictionary API. For this tutorial I have chosen the Oxford Dictionaries, but feel free to use any Dictionary API that your comfortable with.
This may not be the most efficient way to put through a request to the API and process the results, but here is how I did it:
I send an XMLHttpRequest to the API by providing my credentials and adding an event listener to the request. This event listener, when it receives a notification that transactions has been completed, it will parse the results (which is in JSON format). The results I get back contain a ton of information, however all we need for the sake of this tutorial is the first definition returned.
For now, we will place this logic in our toggle method. Don’t forget to define our variable that stores the definition:
We will need to update our view to reflect the new changes we made.
Reload atom and toggle again… Volià!
You did it. Your first plugin, check!
I went a head and added some CSS under the styles folder.
You can find the link to my repository here: https://github.com/kim-codes/kims-dictionary-plugin
Take it for a test drive, add some functionality, improve on it.. but most of all enjoy :)