esy-mode
is a minor mode written for esy - the package manager for
Reason/OCaml development. It is meant to serve as a auxiliary plugin
that helps other plugins to find the correct path to the tools.
For instance, it can help lsp-mode get the right path to ocaml
language server. It, however, doesn’t ship the tools
themselves. esy-mode
simply creates a buffer local environment for
the tools - which enables it to efficiently inform the user of
available/missing tools.
If you are looking for a tool to have a great first working state, checkout pesy. Or simply clone the hello-reason repo.
This minor mode is meant to work with esy
which is not shipped
here. Quickest way to get esy
installed on your machine is to
install it globally using a nodejs package manager
npm i -g esy
# or
yarn global add esy
No, esy
is not written in JS, but a prebuilt binary and is
currently only containing ones that work on 64 bit Windows, Linux
and MacOS. More details on the website
You’ll need to tweak reason-mode
a bit so that the project setup is completely
esy-mode's
hands.
Example: e98f88a244
TODO: make the tweaks less intrusive. Ping me on Discord if you need help with it.
At the moment the package hasn’t been published anywhere. Quickest way to get started is to clone the repo and load it
git clone https://github.com/ManasJayanth/esy-mode
(load-file "/path/to/esy-mode/esy-mode.el")
If you use quelpa and use package, you can use the following
(use-package
esy-mode
:quelpa (esy-mode :path "/path/to/esy-mode.el" :fetcher file)
:hook reason-mode
:config (progn
(lsp-register-client
(make-lsp-client
:new-connection (lsp-stdio-connection '("ocamllsp"))
:major-modes '(reason-mode tuareg-mode)
:server-id 'esy-ocamlmerlin-lsp))))
esy-command
to specify full path to esy command if necessary. (Falls back to a just “esy’)esy-mode-callback
to specify a callback that could run one all buffer local variables are initialised. For more info on the buffer local variables, checkout the next sectionHow it works
.
All npm
and opam
managed Reason/OCaml projects are valid esy projects too.
This means, the minor mode must correctly distinguish them from actual esy
projects
(which are basically Reason/OCaml source with build config files
shipped with an esy.json
or a package.json
).
esy
provides a status
sub-command. Which can return an output
like this in the case of an esy project
{
"isProject": true,
"isProjectSolved": true,
"isProjectFetched": true,
"isProjectReadyForDev": true,
"rootBuildPath": "/path/to/g/foo/_esy/default/store/b/foo-03e8a06e",
"rootInstallPath": "/path/to/g/foo/_esy/default/store/i/foo-03e8a06e",
"rootPackageConfigPath": "/path/to/g/foo/esy.json"
}
For an opam project, it could look like
{
"isProject": true,
"isProjectSolved": true,
"isProjectFetched": true,
"isProjectReadyForDev": true,
"rootBuildPath": "/path/to/ocaml/ocaml-lsp/_esy/default/store/b/ocaml_lsp-38a74123",
"rootInstallPath": "/path/to/ocaml/ocaml-lsp/_esy/default/store/i/ocaml_lsp-38a74123",
"rootPackageConfigPath": null
}
So,
- All non-json manifest file driven projects, by looking up
rootPackageConfigPath
property, are opam projects - Among json file driven projects,
- Those with that are not package.json are esy projects
package.json
withesy
property areesy
projects - others were being managed by npm
Valid esy
projects are straight forward to handle - the minor mode
checks if the project is in buildable state and prompts if it
isn’t.
esy
provides the command environment (the environment where tools
like editors are supposed to run) as a json output. esy-mode
loads
all complete environment in a buffer local
process-environment
, giving each project workspace an identical
development environment. Here on, running (executable-find ...)
returns the dev tools from the esy
sandbox, ensuring you and your
co-worker always have the same exact version of tools while
developing.
esy exec-command <tool-command>
is a great approach. For good
editor experience, one might have to resort to esy exec-command
command -v <tool-command>
repeatedly to check if the tool
exists and inform the user. (executable-find ...)
is better
approach IMO. This is subject to how Emacs handles buffer local
process environments of course.
npm
unfortunately doesn’t provide prebuilts with reproducibility
guarantees, nor does it sandbox tools that need each other on the
path to work together. Mismatching compiler and merlin prebuilts
cause a lot of confusion - using npm to install these tools
globally is not an easy experience for newcomers.
Similarly, inter-tool interaction is not reliable in
global environments. For instance, ocamlmerlin
expects
ocamlmerlin-reason
binary to be available in it’s path - and
both of these must be built with the same version of the
compiler. In the global environment, it was incredibly hard to get
them to work - user’s system wide configuration is a complete
blackbox. The only reliable way to ensure interacting tools work
together is to run them in sandboxed environments - and esy
provides just that!
This is why we recommend bucklescript users to allow editor
plugins to drop an esy.json
- plugins look into the compiler
version and create this file themselves.
This is a work in progress - esy
provides sandboxed environments
for opam projects too (without creating any esy.json
). But opam
users dont ship development time dependencies in their package
manifests. For now, the plugin stays inactive. Ideas are welcome.
Currently beta quality. Looking forward to ideas and feedback. If you’re raising a PR, please add a test. Not having types to catch your errors are hard - even if lisp somehow makes it bearable, let’s ensure we still try to catch errors early!
MIT licensed. Please see LICENSE for more details