hazelgrove / hazel

Hazel, a live functional programming environment with typed holes
http://hazel.org/
MIT License
805 stars 52 forks source link
editor elm functional-programming holes ocaml reasonml

Hazel Build Status

Hazel is a live functional-programming environment rooted in the principles of type theory. You can find the relevant papers and more motivation at the Hazel website.

You can try Hazel online: the dev branch is the main branch at the moment. Every other branch that has been pushed to GitHub and successfully builds can also be accessed at:

https://hazel.org/build/<branch_name>

Building and Running Hazel

Short version

If you already have ocaml version 5.2.0 and at least version 2.0 of opam installed, you can build Hazel by running the following commands.

To view Hazel, you have to serve it, on localhost for development (you can't run it from a file:/// URL due to browser restrictions on e.g. web workers.)

If you have python3 on your path, you can use the Python server via make serve, then navigate to http://0.0.0.0:8000/ in your browser.

Otherwise, run make echo-html-dir which will echo the directory that needs to be served using some other server of your choice.

Long Version

If you are unfamiliar with ocaml or opam, do not have them installed, or just get stuck, we recommend you follow the step-by-step installation instructions contained in INSTALL.md.

Contributing

From OCaml to ReasonML

Hazel is written in ReasonML, which is a syntactic sugar atop OCaml. This link lets you type OCaml and see what the corresponding ReasonML syntax is: https://reasonml.github.io/en/try.

This is useful if you are trying to figure out the ReasonML syntax for something that you know the OCaml syntax for.

You can also convert between OCaml and ReasonML syntax at the terminal using refmt at the terminal. See refmt --help for the details.

Suggested Extensions for VS Code

Most of our team uses Visual Studio Code (VS Code) to write code. If you use VS Code, here are a few extensions that might be helpful.

In addition to these extensions, enabling the breadcrumbs bar can make navigating a large code base easier. There are multiple ways to make the breadcrumbs bar visible:

Suggested Setup for NeoVim

If you enjoy your Vim binding and Vim setup, the following may help you set up your Reason IDE in NeoVim.

If you use vim, I recommend you to switch to NeoVim since it has a better support for multi-thread, and thus less likely to block you when you are programming.

To set up the LSP (Language Server Protocol), you need to set up your Language Client for Neovim and Language Server for ocaml.

After installing the previous two, you may want to copy the following to your neovim config file. (assuming npm have ocaml-language-server installed under /usr/bin)

let g:LanguageClient_serverCommands = {
    \ 'ocaml': ['/usr/bin/ocaml-language-server', '--stdio'],
    \ 'reason': ['/usr/bin/ocaml-language-server', '--stdio']
    \ }
" LanguageClient-neovim
nnoremap <F5> :call LanguageClient_contextMenu()<CR>
" Or map each action separately
nnoremap <silent> K :call LanguageClient#textDocument_hover()<CR>
nnoremap <silent> gd :call LanguageClient#textDocument_definition()<CR>
nnoremap <silent> gr :call LanguageClient#textDocument_references()<CR>
nnoremap <silent> gf :call LanguageClient#textDocument_formatting()<cr>
nnoremap <silent> <F2> :call LanguageClient#textDocument_rename()<CR>

Build System Details

Hazel is compiled to Javascript for the web browser via the js_of_ocaml compiler.

Though make targets are provided as a convenience, they mostly translate to dune commands.

Invoking make by itself is equivalent to invoking make dev. With these commands we pass additional flags to js_of_ocaml that cause the insertion of comments that map locations in the generated JS to locations in the source files. This is useful for debugging purposes.

make dev also auto-formats Reason source files using refmt (this is what the @src/fmt alias is for). This ensures code from all contributors follows the same style.

The make dev and make release commands do three things:

  1. Generate some internal parsers using menhir.
  2. Compile the Reason code to OCaml bytecode using the OCaml compiler.
  3. Compile the OCaml bytecode to JavaScript (_build/default/src/hazelweb/www/hazel.js) using js_of_ocaml.

For a smoother dev experience, use make watch to automatically watch for file changes. This may require installing fswatch (see INSTALL.md). You can also run make watch-release to continuously build the release build (takes longer per build).

Clean Build

To obtain an clean build, you may need to:

This sets up a standalone OCaml environment in the cloned project, independent of the one you sent in your home directory. This allow you to alternate dependencies, or test dependencies changes, without affect existing OCaml projects.

NOTE: You may see the following warning when building:

Warning 58 [no-cmx-file]: no cmx file was found in path for module Ezjs_idb, and its interface was not compiled with -opaque

This is due to an upstream library issue and does not cause problems with Hazel:

https://github.com/OCamlPro/ezjs_idb/issues/1

Debugging

Printing

You can print to the browser console using the standard print_endline function. This is probably the easiest method right now. Most datatypes in the codebase have something like [@deriving (show({with_path: false}), sexp, yojson)] on them. This generates helper functions for printing and serializing this data. For a type named t, the show function will be named show. Otherwise, for a type named something else like q, it will be show_q.

Source Maps

Source maps for js_of_ocaml should be configured when making locally with the dev profile (make). This is configured using the env stanzas present in the dune files for each top-level directory.

Since source maps are generated browser developer tools should show reason code in the debugger and source tree. Stack traces should also include reason line numbers.

Debug Mode

If Hazel is hanging on load or when you perform certain actions, you can load into Debug Mode by appending #debug to the URL and reloading. From there, you have some buttons that will change settings or reset local storage. Refresh without the #debug flag and hopefully you can resolve the situation from there.

Testing

You can run all of the unit tests located in test by running make test.

Unit tests are written using the Alcotest framework.

Coverage

Code coverage is provided by bisect_ppx. To collect coverage statistics from tests run make coverage. After coverage statistics are generated, running make generate-coverage-html will generate a local webpage at _coverage/index.html that can be viewed to see line coverage per module.

Continuous Integration

When you push your branch to the main hazelgrove/hazel repository, we have a GitHub Action setup (see .github/workflows/deploy_branches.yml) that will build that branch (in release mode) and deploy it to the URL https://hazel.org/build/<branch name>, assuming the build succeeds.

It usually takes about 2 minutes if the build environment cache hits, or 20+ minutes if not. You can view the status of the build in the Actions tab on Github.

Builds prior to July 2024 are archived at https://hazel.org/build/<branch name>.

Note: If another archive needs to be performed, make sure to redeploy the following branches manually since we refer to them in various public material (websites and published papers):

dev livelits