roc/crates/editor
Joshua Warner a046428ce6
Add fuzzing for the formatter and fix bugs
This commit adds fuzzing for the (expr) formatter, with the same invariants that we use for fmt tests:
  * We start with text, which we parse
  * We format the AST, which must succeed
  * We parse back the AST and make sure it's identical igoring whitespace+comments
  * We format the new AST and assert it's equal to the first formatted version ("idempotency")

Interestingly, while a lot of bugs this found were in the formatter, it also found some parsing bugs.

It then fixes a bunch of bugs that fell out:
* Some small oversights in RemoveSpaces
* Make sure `_a` doesn't parse as an inferred type (`_`) followed by an identifier (parsing bug!)
* Call `extract_spaces` on a parsed expr before matching on it, lest it be Expr::SpaceBefore - when parsing aliases
* A few cases where the formatter generated invalid/different code
* Numerous formatting bugs that caused the formatting to not be idempotent

The last point there is worth talking further about. There were several cases where the old code was trying to enforce strong
opinions about how to insert newlines in function types and defs. In both of those cases, it looked like the goals of
(1) idempotency, (2) giving the user some say in the output, and (3) these strong opinions - were often in conflict.

For these cases, I erred on the side of following the user's existing choices about where to put newlines.

We can go back and re-add this strong opinionation later - but this seemed the right approach for now.
2022-12-17 09:52:09 -08:00
..
src Make roc_cache_dir() panic if it can't find $HOME 2022-11-20 20:54:03 -05:00
tests Add fuzzing for the formatter and fix bugs 2022-12-17 09:52:09 -08:00
Cargo.toml Make fs_extra a workspace dependency 2022-12-01 22:33:04 -05:00
creature.png moved all crates into seperate folder + related path fixes 2022-07-01 17:37:43 +02:00
Inconsolata-Regular.ttf moved all crates into seperate folder + related path fixes 2022-07-01 17:37:43 +02:00
README.md Repair links in Markdown 2022-10-11 18:36:15 -04:00
snippet-ideas.md Add missing h1s 2022-09-09 01:12:32 -06:00

🚧 Work In Progress 🚧

The editor is a work in progress, only a limited subset of Roc expressions are currently supported.

Unlike most editors, we use projectional or structural editing to edit the Abstract Syntax Tree directly. This will allow for cool features like excellent auto-complete, refactoring and never needing to format your code.

Getting started

  • Install the compiler, see here.
  • Run the following from the roc folder:
cargo run edit

Troubleshooting

If you encounter problems with integrated graphics hardware, install mesa-vulkan-drivers and vulkan-tools.

If you encounter an error like gfx_backend_vulkan ... Failed to detect any valid GPUs in the current config ... make sure the correct graphics card drivers are installed. On ubuntu sudo ubuntu-drivers autoinstall can resolve the problem. If the error persists, take a look here to see if your GPU supports vulkan. Use of OpenGL instead of vulkan should be available in several months.

Make sure to create an issue if you encounter any problems not listed above.

Inspiration

We thank the following open source projects in particular for inspiring us when designing the Roc editor:

How does it work?

To take a look behind the scenes, open the editor with ./roc edit or cargo run edit and press F11. This debug view shows important data structures that can be found in editor/src/editor/mvc/ed_model.rs. Add or delete some code to see how these data structures are updated.

From roc to render:

  • ./roc edit or cargo run edit is first handled in cli/src/main.rs, from there the editor's launch function is called (editor/src/editor/main.rs).
  • In run_event_loop we initialize the winit window, wgpu, the editor's model(EdModel) and start the rendering loop.
  • The ed_model is filled in part with data obtained by loading and typechecking the roc file with the same function (load_and_typecheck) that is used by the compiler.
  • ed_model also contains an EdModule, which holds the parsed abstract syntax tree (AST).
  • In the init_model function:
    • The AST is converted into a tree of MarkupNode. The different types of MarkupNode are similar to the elements/nodes in HTML. A line of roc code is represented as a nested MarkupNode containing mostly text MarkupNodes. The line foo = "bar" is represented as three text MarkupNode; representing foo, = and bar. Multiple lines of roc code are represented as nested MarkupNode that contain other nested MarkupNode.
    • CodeLines holds a Vec of String, each line of code is a String. When saving the file, the content of CodeLines is written to disk.
    • GridNodeMap maps every position of a char of roc code to a MarkNodeId, for easy interaction with the caret.
  • Back in editor/src/editor/main.rs we convert the EdModel to RenderedWgpu by calling model_to_wgpu.
  • The RenderedWgpu is passed to the glyph_brush to draw the characters(glyphs) on the screen.

Important files

To understand how the editor works it is useful to know the most important files:

  • editor/src/editor/main.rs
  • editor/src/editor/mvc/ed_update.rs
  • editor/src/editor/mvc/ed_model.rs
  • editor/src/editor/mvc/ed_view.rs
  • editor/src/editor/render_ast.rs
  • editor/src/editor/render_debug.rs

Important folders/files outside the editor folder:

  • code_markup/src/markup/convert
  • code_markup/src/markup/nodes.rs
  • ast/src/lang/core/def
  • ast/src/lang/core/expr
  • ast/src/lang/core/ast.rs
  • ast/src/lang/env.rs

Contributing

We welcome new contributors ❤️ and are happy to help you get started. Check CONTRIBUTING.md for more info.