So I have the following code I copied (by hand) from the online tutorial:
app [main] {
pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br",
}
import pf.Stdout
import pf.Task
main =
Stdout.line! "I'm a Roc application!"
This refuses to compile because the last line isn't indented. I would have expected the code formatter to run first but is that expectation a bad one?
The reason I didn't indent is that I hit <RETURN>
after writing main =
and the editor I'm using (Zed at the moment) didn't indent so I just assumed it would be handled by the code formatter.
The code doesn't parse, so I don't think the formatter can fix it.
Running the formatter manually gives.
$ roc format testa.roc
We ran into an issue while compiling your code.
Sadly, we don't have a pretty error message for this case yet.
If you can't figure out the problem from the context below, please reach out at: https://roc.zulipchat.com/
Unexpected parse failure when parsing this formatting:
"app [main] {\n pf: platform \"https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br\",\n}\n\nimport pf.Stdout\nimport pf.Task\n\nmain =\nStdout.line! \"I'm a Roc application!\"\n"
Parse error was:
Expr(IndentEnd(@189), @148)
I guess another question is should it be able to parse? or can it be made to parse this reliably?
I think @Joshua Warner was working on a related upgrade to the parser using the concept of blocks. Maybe he has some thoughts on this.
I guess my other question is 'If it's an error not to indent after writing main =
and starting a newline, should Zed not be indenting automatically?'
There's a lot going on here actually ;)
That code in and of itself isn't ambiguous and we could parse it just fine if we wanted to
However - that quickly becomes no longer true if you put anything after that last line, since we wouldn't be able to disambiguate whether you meant for that to be part of the main =
or be part of the global scope
Thanks for the reply, @Joshua Warner :) I appreciate this perhaps isn't your area but am I correct in thinking there's no ambiguity that when I hit Return after writing main =
, the editor should indent?
I think VS Code extension does this sometimes, but the zed one doesn't. Maybe its a language server thing? or specific to certain editors?
it should be specific to editors, the language server takes as configuration whether the client (editor) wants code formating changes
In the Emacs roc-mode package, we mostly use tree-sitter-based indentation, but I couldn't figure out a way to solve this problem using tree-sitter. So I ended up using a heuristic that seems to work okay: if the previous line (skipping blank lines and ignoring comments) ends with =
, [
, {
, (
, ->
, :
, expect-fx
, is
, then
, else
, expect
, where
, dbg
, app
, package
, platform
, module
, exposes
, imports
, import
, with
, packages
, requires
, or provides
, then indent the current line by 4 spaces more than the previous line.
Last updated: Jul 06 2025 at 12:14 UTC