Molecule implements several concepts in order to achieve a unified experience, those concepts can be confusing for new-comers, so this part of the documentation will help you get through all of them.
Molecule automatically searches for packages in a folder, and ask plugins whether it's considered as a package for their tools.
Molecule is an Integrated Development Environment, and as every IDE, it has to support different stacks and tools for the developer to have access to the everyday tooling he's used to work with. To make easier the integration of those tools, Molecule provide several APIs that handle a big part of the work required to integrate a tool.
Therefore a plugin is a link between Atom and the integrated tool, that define how molecule has to execute a tool and how the returned data has to be interpreted, to provide a unified visualization to the developer.
A plugin is made of two parts: an Atom plugin and a NPM package.
This separation is made to allow Molecule to execute remotely the tools by installing them through NPM on the remote machine. The Atom plugin is made to handle the developer experience side of the tool, and so the user interface specific to the tool, and others details appearing only on Atom.
Each plugin can define handlers that will be called on different tool events, like a new output or the tool exit. Handlers are defined in the NPM package. An example of a handler is the isPackage one, which is called by Molecule to check if a path is considered as a package for the plugin.
The code related to the loading of plugin is in ExecutionControlEpic/DevtoolLoadingFeature/
Molecule provides to the developer reusable actions, that are ways of using a tool. For example, a build tool can provide a debug build action and a production build action. Molecule call them "plans" and the user interface is designed around them. Each plugin can provide a configuration for the user to configure plans, and can automatically generate some others.
A plan is basically a structure that contains an id, a name, the tool it comes from, the project it is associated with and a configuration. The configuration is custom and completely specific to the definition made by the plugin. It also contains information about whether the plan is automatically generated, if it has to be automatically launched and UI preferences.
The code related to plans is in ExecutionControlEpic/PlanConfigurationFeature/
The plan configuration depends on some user inputs, and so it is somehow a way for Molecule to save this input. But because the configuration is specific to each plugin, Molecule doesn't know what to do with it, it can't interpret what it means and how it will lead to a tool execution.
What Molecule can understand is a structure called strategy. A strategy is a definition of how to execute a tool. In simple words, it's a description of the method Molecule has to use to execute the tool. Many methods are available: through a shell, through a node fork process, through a pty. Each methods require different additional configuration attributes.
This description called strategy is generated by the plugin as a response to the plan configuration. So a plan configuration is sent to the plugin, which then generates a strategy from it.
The code related to strategies is in ExecutionControlEpic/LanguageServerProtocolFeature/Model/
Once the strategy is generated, it is interpreted by what we call a runner. Each strategy has a type (a word describing the method) and each type is associated with a specific runner. The runner is called to run or stop a strategy.
It's basically a generic interface to make easy the addition of new ways of executing tools in Molecule. It provides a unified API for any kind of tool execution.
Because Molecule supports language servers (with the Language Server Protocol, LSP), each runner has the ability to define whether it supports it or not. Indeed, some strategy involves unreadable outputs (like the pty strategy which makes use of ansii codes) leading to the inability to parse the LSP. It's the role of the runner to tell this information to Molecule.
The code related to runners is in ExecutionControlEpic/LanguageServerProtocolFeature/Model/
It has the responsibility to execute the runner, to stop it, and to proxy data between the core and the runner. It also has the responsibility to call the plugin handlers.
The code related to the Controller is in ExecutionControlEpic/LanguageServerProtocolFeature/Model/
LSP (Language Server Protocol) communications are made through and with the Controller. Those communications can notify the Core of many changes including the busy state of a process, new diagnostics, new terminal output. Some of the features are enhancements on the original Language Server Protocol, an extension made by us to handle features undefined in the protocol.
If the process executed is ran by a strategy runner which supports language servers (and so is a language server), all the communications specified in the protocol are proxied by the Controller to the process. All the unspecified communications are only handled by the controller which knows what to do with it, without being proxied to the running process.
If the running process is not a language server, the Controller is the only handler of the messages.
Molecule has an architecture that allows it to execute tools remotely, and for that, it had to provide a way to execute strategy runners and so the controller at different places. This is the role of the stager.
The stager is a tunnel between the core of Molecule and the Controller. This tunnel works as a double stream and can be a simple process execution (Local Stager) which uses stdout/stdin or an SSH connection (Remote Stager) which uses the network.
It has many roles:
- to initiate the infrastructure to proxy data between the controller and the core
- to run the controller
- to provide an input stream, an output stream and an event emitter for specific events (controller killed, exit, etc ...).
The code related to stagers is in ExecutionControlEpic/LanguageServerProtocolFeature/Model/