Merge branch 'main' into inline-imports

This commit is contained in:
Agus Zubiaga 2024-05-01 10:25:17 -03:00
commit eb8ef6241e
No known key found for this signature in database
24 changed files with 182 additions and 180 deletions

View file

@ -949,15 +949,16 @@ mod cli_run {
This roc file can print its own source code. The source is:
app "ingested-file"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [
pf.Stdout,
pf.Task,
"ingested-file.roc" as ownCode : Str,
]
provides [main] to pf
main =
Stdout.line "\nThis roc file can print its own source code. The source is:\n\n$(ownCode)"
Stdout.line! "\nThis roc file can print its own source code. The source is:\n\n$(ownCode)"
"#
),

View file

@ -1816,7 +1816,7 @@ fn roc_file_no_extension() {
indoc!(
r#"
app "helloWorld"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [pf.Stdout]
provides [main] to pf

View file

@ -1,7 +1,7 @@
app "hello"
packages {
pf:
"https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br",
"https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br",
}
imports [pf.Stdout]
provides [main] to pf

View file

@ -17,14 +17,14 @@ Full {
after: [],
},
item: [
@27-145 SpaceAfter(
@27-146 SpaceAfter(
PackageEntry {
shorthand: "pf",
spaces_after_shorthand: [
Newline,
],
package_name: @31-145 PackageName(
"https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br",
package_name: @31-146 PackageName(
"https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br",
),
},
[
@ -44,7 +44,7 @@ Full {
after: [],
},
item: [
@161-170 Package(
@162-171 Package(
"pf",
ModuleName(
"Stdout",
@ -63,7 +63,7 @@ Full {
after: [],
},
entries: [
@186-190 ExposedName(
@187-191 ExposedName(
"main",
),
],
@ -73,7 +73,7 @@ Full {
item: ToKeyword,
after: [],
},
to: @195-197 ExistingPackage(
to: @196-198 ExistingPackage(
"pf",
),
},
@ -85,7 +85,7 @@ Full {
Index(2147483648),
],
regions: [
@199-246,
@200-247,
],
space_before: [
Slice(start = 0, length = 2),
@ -100,17 +100,17 @@ Full {
type_defs: [],
value_defs: [
Body(
@199-203 Identifier {
@200-204 Identifier {
ident: "main",
},
@210-246 SpaceBefore(
@211-247 SpaceBefore(
Apply(
@210-221 Var {
@211-222 Var {
module_name: "Stdout",
ident: "line",
},
[
@222-246 Str(
@223-247 Str(
PlainLine(
"I'm a Roc application!",
),

View file

@ -1,6 +1,6 @@
app "hello"
packages { pf:
"https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br"
"https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br"
}
imports [pf.Stdout]
provides [main] to pf

View file

@ -74,7 +74,8 @@ impl Registry {
if &document.doc_info.url == updating_url {
//Write the newly analysed document into the oncelock that any request requiring the latest document will be waiting on
if let Some(a) = documents.get_mut(updating_url) {
a.latest_document.set(document.clone()).unwrap()
// We don't care if this fails because we expect the document to sometimes already be there
a.latest_document.set(document.clone()).unwrap_or(())
}
}

View file

@ -3,7 +3,7 @@ use analysis::HIGHLIGHT_TOKENS_LEGEND;
use log::{debug, trace};
use registry::{Registry, RegistryConfig};
use std::future::Future;
use std::panic::AssertUnwindSafe;
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::time::Duration;
use tower_lsp::jsonrpc::{self, Result};
@ -173,9 +173,24 @@ impl RocServerState {
return Err("Not latest version skipping analysis".to_string());
}
let results = match tokio::task::spawn_blocking(|| global_analysis(doc_info)).await {
Err(e) => return Err(format!("Document analysis failed. reason:{:?}", e)),
Ok(a) => a,
let results = match tokio::time::timeout(
Duration::from_secs(60),
tokio::task::spawn_blocking(|| catch_unwind(|| global_analysis(doc_info))),
)
.await
{
Err(e) => {
return Err(format!(
"Document analysis thread timeout out after: {:?}",
e
))
}
Ok(Err(e)) => {
return Err(format!("Document analysis thread failed. reason:{:?}", e))
}
Ok(Ok(res)) => {
res.map_err(|err| format!("Document analysis panicked with: {:?}", err))?
}
};
let latest_version = inner_ref.registry.get_latest_version(fi).await;
@ -230,8 +245,11 @@ impl LanguageServer for RocServer {
// NOTE: We specify that we expect full-content syncs in the server capabilities,
// so here we assume the only change passed is a change of the entire document's content.
let TextDocumentContentChangeEvent { text, .. } =
params.content_changes.into_iter().next().unwrap();
let TextDocumentContentChangeEvent { text, .. } = params
.content_changes
.into_iter()
.last()
.expect("textDocument change event had no changes ");
self.change(uri, text, version).await;
}

View file

@ -1,11 +1,10 @@
app "args"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [pf.Stdout, pf.Arg, pf.Task.{ Task }]
provides [main] to pf
main : Task {} I32
main =
args <- Arg.list |> Task.await
args = Arg.list!
parser =
divCmd =
Arg.succeed (\dividend -> \divisor -> Div (Num.toF64 dividend) (Num.toF64 divisor))
@ -55,9 +54,8 @@ main =
|> Num.toStr
|> Stdout.line
Err helpMenu ->
{} <- Stdout.line helpMenu |> Task.await
Task.err 1
Err helpMenuErr ->
Task.err (Exit 1 "unable to parse args: $(Inspect.toStr helpMenuErr)")
runCmd = \cmd ->
when cmd is

View file

@ -1,5 +1,5 @@
app "countdown"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [pf.Stdin, pf.Stdout, pf.Task.{ await, loop }]
provides [main] to pf

View file

@ -1,21 +1,19 @@
app "echo"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [pf.Stdin, pf.Stdout, pf.Task.{ Task }]
provides [main] to pf
main : Task {} I32
main =
_ <- Task.await (Stdout.line "🗣 Shout into this cave and hear the echo! 👂👂👂")
Task.loop {} tick
tick : {} -> Task [Step {}, Done {}] *
tick : {} -> Task [Step {}, Done {}] _
tick = \{} ->
shout <- Task.await Stdin.line
when shout is
Input s -> Stdout.line (echo s) |> Task.map Step
End -> Stdout.line (echo "Received end of input (EOF).") |> Task.map Done
when Stdin.line |> Task.result! is
Ok str -> Stdout.line (echo str) |> Task.map Step
Err (StdinErr EndOfFile) -> Stdout.line (echo "Received end of input (EOF).") |> Task.map Done
Err (StdinErr err) -> Stdout.line (echo "Unable to read input $(Inspect.toStr err)") |> Task.map Done
echo : Str -> Str
echo = \shout ->

View file

@ -1,9 +1,8 @@
app "env"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [pf.Stdout, pf.Stderr, pf.Env, pf.Task.{ Task }]
provides [main] to pf
main : Task {} I32
main =
task =
Env.decode "EDITOR"

View file

@ -1,8 +1,7 @@
app "file-io"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [
pf.Stdout,
pf.Stderr,
pf.Task.{ Task },
pf.File,
pf.Path,
@ -11,26 +10,23 @@ app "file-io"
]
provides [main] to pf
main : Task {} I32
main : Task {} [Exit I32 Str]_
main =
path = Path.fromStr "out.txt"
task =
cwd <- Env.cwd |> Task.await
cwdStr = Path.display cwd
_ <- Stdout.line "cwd: $(cwdStr)" |> Task.await
dirEntries <- Dir.list cwd |> Task.await
cwd = Env.cwd!
Stdout.line! "cwd: $(Path.display cwd)"
dirEntries = Dir.list! cwd
contentsStr = Str.joinWith (List.map dirEntries Path.display) "\n "
Stdout.line! "Directory contents:\n $(contentsStr)\n"
Stdout.line! "Writing a string to out.txt"
File.writeUtf8! path "a string!"
contents = File.readUtf8! path
Stdout.line! "I read the file back. Its contents: \"$(contents)\""
_ <- Stdout.line "Directory contents:\n $(contentsStr)\n" |> Task.await
_ <- Stdout.line "Writing a string to out.txt" |> Task.await
_ <- File.writeUtf8 path "a string!" |> Task.await
contents <- File.readUtf8 path |> Task.await
Stdout.line "I read the file back. Its contents: \"$(contents)\""
Task.attempt task \result ->
when result is
Ok {} -> Stdout.line "Successfully wrote a string to out.txt"
when Task.result! task is
Ok {} -> Stdout.line! "Successfully wrote a string to out.txt"
Err err ->
msg =
when err is
@ -40,5 +36,4 @@ main =
FileReadErr _ _ -> "Error reading file"
_ -> "Uh oh, there was an error!"
{} <- Stderr.line msg |> Task.await
Task.err 1
Task.err (Exit 1 msg)

View file

@ -1,20 +1,12 @@
app "form"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
imports [pf.Stdin, pf.Stdout, pf.Task.{ await, Task }]
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [pf.Stdin, pf.Stdout, pf.Task]
provides [main] to pf
main : Task {} I32
main =
_ <- await (Stdout.line "What's your first name?")
firstName <- await Stdin.line
Stdout.line! "What's your first name?"
firstName = Stdin.line!
Stdout.line! "What's your last name?"
lastName = Stdin.line!
_ <- await (Stdout.line "What's your last name?")
lastName <- await Stdin.line
Stdout.line "Hi, $(unwrap firstName) $(unwrap lastName)! 👋"
unwrap : [Input Str, End] -> Str
unwrap = \input ->
when input is
Input line -> line
End -> "Received end of input (EOF)."
Stdout.line "Hi, $(firstName) $(lastName)! 👋"

View file

@ -1,31 +1,23 @@
app "http-get"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
imports [pf.Http, pf.Task.{ Task }, pf.Stdin, pf.Stdout]
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [pf.Http, pf.Task, pf.Stdout]
provides [main] to pf
main : Task {} I32
main =
_ <- Task.await (Stdout.line "Enter a URL to fetch. It must contain a scheme like \"http://\" or \"https://\".")
input <- Task.await Stdin.line
when input is
End ->
Stdout.line "I received end-of-input (EOF) instead of a URL."
Input url ->
request = {
method: Get,
headers: [],
url,
url: "http://www.example.com",
mimeType: "",
body: [],
timeout: NoTimeout,
timeout: TimeoutMilliseconds 5000,
}
output <- Http.send request
|> Task.await \resp -> resp |> Http.handleStringResponse |> Task.fromResult
|> Task.onErr \err -> crash (Http.errorToString err)
|> Task.await
resp = Http.send! request
output =
when resp |> Http.handleStringResponse is
Err err -> crash (Http.errorToString err)
Ok body -> body
Stdout.line output

View file

@ -1,7 +1,8 @@
app "ingested-file-bytes"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [
pf.Stdout,
pf.Task,
"../../LICENSE" as license : _, # A type hole can also be used here.
]
provides [main] to pf
@ -12,4 +13,4 @@ main =
|> List.map Num.toU64
|> List.sum
|> Num.toStr
|> Stdout.line
|> Stdout.line!

View file

@ -1,10 +1,11 @@
app "ingested-file"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [
pf.Stdout,
pf.Task,
"ingested-file.roc" as ownCode : Str,
]
provides [main] to pf
main =
Stdout.line "\nThis roc file can print its own source code. The source is:\n\n$(ownCode)"
Stdout.line! "\nThis roc file can print its own source code. The source is:\n\n$(ownCode)"

View file

@ -1,7 +1,7 @@
app "helloWorld"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
imports [pf.Stdout]
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [pf.Stdout, pf.Task]
provides [main] to pf
main =
Stdout.line "Hello, World!"
Stdout.line! "Hello, World!"

View file

@ -2,9 +2,10 @@
# Shows how Roc values can be logged
#
app "inspect-logging"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [
pf.Stdout,
pf.Task,
Community,
]
provides [main] to pf
@ -35,4 +36,4 @@ main =
|> Community.addFriend 0 2
|> Community.addFriend 1 2
|> Inspect.toStr
|> Stdout.line
|> Stdout.line!

View file

@ -1,11 +1,12 @@
app "example"
packages {
cli: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br",
cli: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br",
parser: "https://github.com/lukewilliamboswell/roc-parser/releases/download/0.5.2/9VrPjwfQQ1QeSL3CfmWr2Pr9DESdDIXy97pwpuq84Ck.tar.br",
}
imports [
cli.Stdout,
cli.Stderr,
cli.Task,
parser.Core.{ Parser, buildPrimitiveParser, many },
parser.String.{ parseStr },
]

View file

@ -1,12 +1,12 @@
app "example"
packages {
pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br",
pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br",
parser: "https://github.com/lukewilliamboswell/roc-parser/releases/download/0.5.2/9VrPjwfQQ1QeSL3CfmWr2Pr9DESdDIXy97pwpuq84Ck.tar.br",
}
imports [
pf.Stdout,
pf.Stderr,
pf.Task.{ Task },
pf.Task,
parser.Core.{ Parser, map, keep },
parser.String.{ strFromUtf8 },
parser.CSV.{ CSV },
@ -16,7 +16,6 @@ app "example"
input : Str
input = "Airplane!,1980,\"Robert Hays,Julie Hagerty\"\r\nCaddyshack,1980,\"Chevy Chase,Rodney Dangerfield,Ted Knight,Michael O'Keefe,Bill Murray\""
main : Task {} *
main =
when CSV.parseStr movieInfoParser input is
Ok movies ->

View file

@ -70,9 +70,3 @@ These are planned changes to how things work, which should be backwards-compatib
This doesn't come up a lot, but [the feature](https://github.com/roc-lang/roc/issues/5504) basically means you can match on some tags in a `when`, and then have an `other ->` branch which has the tags you already matched on removed from the union. That means if you later do another `when` on the `other` value, you won't have to match on (or use `_ ->` to ignore) the tags you already matched in the first `when`, like you do today.
This is planned but nobody is currently working on it. It's a quality of life improvement but doesn't unblock anything; today you can just add a `_ ->` branch to the inner `when`, which is undesirable but not a blocker.
### [`Inspect` Inference](#inspect-inference) {#inspect-inference}
When this lands, all Roc types will have a default `implements Inspect`, which you can override if desired. `dbg` will use it to display things, which in turn means you'll be able to customize `dbg` output. Also it will mean you can do things like turning any Roc type into a string and writing it to a log file.
Note that in this design, functions will have an `Inspect` implementation which essentially renders them as `"<function>"` with no other information, and opaque types will be `"<opaque>"` by default unless you customize them. This is important because neither functions nor opaque types should expose their internal details, so that you can safely refactor them without causing regressions in distant parts of the code base because something depended on an internal implementation detail.

View file

@ -8,8 +8,8 @@ Here is a Roc application that prints `"Hello, World!"` to the command line:
```roc
app "hello"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
imports [pf.Stdout]
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [pf.Stdout, pf.Task]
provides [main] to pf
main =

View file

@ -155,8 +155,8 @@ Make a file named `main.roc` and put this in it:
```roc
app "hello"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
imports [pf.Stdout]
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [pf.Stdout, pf.Task]
provides [main] to pf
main =
@ -1455,7 +1455,7 @@ Let's take a closer look at the part of `main.roc` above the `main` def:
```roc
app "hello"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [pf.Stdout]
provides [main] to pf
```
@ -1467,7 +1467,7 @@ The line `app "hello"` shows that this module is a Roc application. The "hello"
The remaining lines all involve the [platform](https://github.com/roc-lang/roc/wiki/Roc-concepts-explained#platform) this application is built on:
```roc
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [pf.Stdout]
provides [main] to pf
```
@ -1566,7 +1566,7 @@ Let's start with a basic "Hello World" program.
```roc
app "cli-tutorial"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [pf.Stdout]
provides [main] to pf
@ -1600,7 +1600,7 @@ Let's change `main` to read a line from `stdin`, and then print what we got:
```roc
app "cli-tutorial"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.9.1/y_Ww7a2_ZGjp0ZTt9Y_pNdSqqMRdMLzHMKfdN8LWidk.tar.br" }
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
imports [pf.Stdout, pf.Stdin, pf.Task]
provides [main] to pf
@ -1630,7 +1630,7 @@ high-quality programs handle errors gracefully. Fortunately, we can do this nice
If we wanted to add the type annotation to `main` that Roc is inferring for it, we would add this annotation:
```roc
main : Task {} [Exit I32, StdoutErr Stdout.Err, StinErr Stdin.Err]
main : Task {} [Exit I32, StdoutErr Stdout.Err, StdinErr Stdin.Err]
main =
```
@ -1638,7 +1638,7 @@ Let's break down what this type is saying:
- `Task` tells us this is a `Task` type. Its two type parameters are just like the ones we saw in `Result` earlier: the first type tells us what this task will produce if it succeeds, and the other one tells us what it will produce if it fails.
- `{}` tells us that this task always produces an empty record when it succeeds. (That is, it doesn't produce anything useful. Empty records don't have any information in them!) This is because the last task in `main` comes from `Stdout.line`, which doesn't produce anything. (In contrast, the `Stdin` task's first type parameter is a `Str`, because it produces a `Str` if it succeeds.)
- `[Exit I32, StdoutErr Stdout.Err, StinErr Stdin.Err]` tells us the different ways this task can fail. The `StdoutErr` and `StdinErr` tags are there becase we used `Stdout.line` and `Stdin.line`. We'll talk about `Exit I32` more in a moment.
- `[Exit I32, StdoutErr Stdout.Err, StdinErr Stdin.Err]` tells us the different ways this task can fail. The `StdoutErr` and `StdinErr` tags are there becase we used `Stdout.line` and `Stdin.line`. We'll talk about `Exit I32` more in a moment.
To understand what the `Exit I32 Str` error means, let's try temporarily commenting out our current `main` and replacing
it with this one:
@ -1666,7 +1666,7 @@ In summary:
### [Handling task failures](#handling-task-failures) {#handling-task-failures}
If the `main` task ends up failing with any other errors besides `Exit` (such as `StdoutErr` or `StdinErr`), then the `basic-cli` platform's automatic error handling will handle them by printing out words taken from the source code (such as "StdoutErr" and "StinErr"), which could lead to a bad experience for people using this program!
If the `main` task ends up failing with any other errors besides `Exit` (such as `StdoutErr` or `StdinErr`), then the `basic-cli` platform's automatic error handling will handle them by printing out words taken from the source code (such as "StdoutErr" and "StdinErr"), which could lead to a bad experience for people using this program!
We can prevent that by gracefully handling the other error types, and then translating them into `Exit` errors so that they affect the program's exit code and don't result in the platform printing anything. A convenient way to make sure we've handled all the other errors is to keep our current type annotation for `main` but restore our old implementation:

View file

@ -39,6 +39,7 @@
--header-link-color: #1bbcb3;
--header-link-hover: #222;
--h1-color: #8055e4;
--tutorial-h3-color: #8c5ce3; /* Slightly darker than --primary-1, which looks washed-out in <h3>s */
}
html {
@ -167,7 +168,7 @@ hr {
}
#sponsor-logos .logo-decem .cls-1 {
fill:#04021e;
fill: #04021e;
}
#sponsor-logos + p {
@ -731,7 +732,8 @@ li {
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/permanent-marker-v16-latin/permanent-marker-v16-latin-regular.woff2")
src:
url("/fonts/permanent-marker-v16-latin/permanent-marker-v16-latin-regular.woff2")
format("woff2"),
url("/fonts/permanent-marker-v16-latin/permanent-marker-v16-latin-regular.woff")
format("woff");
@ -746,7 +748,8 @@ li {
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/lato-v23-latin-ext_latin/lato-v23-latin-ext_latin-regular.woff2")
src:
url("/fonts/lato-v23-latin-ext_latin/lato-v23-latin-ext_latin-regular.woff2")
format("woff2"),
url("/fonts/lato-v23-latin-ext_latin/lato-v23-latin-ext_latin-regular.woff")
format("woff");
@ -760,7 +763,8 @@ li {
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/lato-v23-latin/lato-v23-latin-regular.woff2")
src:
url("/fonts/lato-v23-latin/lato-v23-latin-regular.woff2")
format("woff2"),
url("/fonts/lato-v23-latin/lato-v23-latin-regular.woff") format("woff");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
@ -774,7 +778,8 @@ li {
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/source-code-pro-v22-latin-ext_latin/source-code-pro-v22-latin-ext_latin-regular.woff2")
src:
url("/fonts/source-code-pro-v22-latin-ext_latin/source-code-pro-v22-latin-ext_latin-regular.woff2")
format("woff2"),
url("/fonts/source-code-pro-v22-latin-ext_latin/source-code-pro-v22-latin-ext_latin-regular.woff")
format("woff");
@ -788,7 +793,8 @@ li {
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/source-code-pro-v22-latin/source-code-pro-v22-latin-regular.woff2")
src:
url("/fonts/source-code-pro-v22-latin/source-code-pro-v22-latin-regular.woff2")
format("woff2"),
url("/fonts/source-code-pro-v22-latin/source-code-pro-v22-latin-regular.woff")
format("woff");
@ -825,6 +831,7 @@ li {
--header-link-color: #9c7cea;
--header-link-hover: #ddd;
--h1-color: #1bc6bd;
--tutorial-h3-color: var(--primary-1);
}
.logo-dark {
@ -1137,7 +1144,8 @@ code .dim {
color: #7c38f5;
}
.interactive-desc code, .interactive-desc pre {
.interactive-desc code,
.interactive-desc pre {
background: none;
color: inherit;
}
@ -1201,9 +1209,12 @@ code .dim {
border: none;
}
#tutorial-main h3 a {
color: var(--tutorial-h3-color);
}
#tutorial-main h1 a,
#tutorial-main h2 a,
#tutorial-main h3 a,
#tutorial-main h4 a,
#tutorial-main h5 a {
color: var(--header-link-color);
@ -1240,7 +1251,7 @@ code .dim {
font-family: inherit;
font-size: 1.65rem;
line-height: 3rem;
text-shadow: 1px 1px 1px #010101;
margin-bottom: 0.5rem;
}
#tutorial-main h4 {
@ -1364,12 +1375,14 @@ code .dim {
font-size: 18px;
}
#homepage-repl-container #repl-prompt, #homepage-repl-container .input-line-prefix {
#homepage-repl-container #repl-prompt,
#homepage-repl-container .input-line-prefix {
top: 1.25rem;
color: var(--light-cyan);
}
.input-line-prefix, #repl-prompt {
.input-line-prefix,
#repl-prompt {
color: var(--cyan);
color: var(--primary-2);
}
@ -1481,7 +1494,7 @@ code .dim {
in a light color scheme, and only white in dark mode. The name could be better!
*/
#homepage-repl-container .color-white {
color: #FFF;
color: #fff;
}
#repl-container .color-white {
@ -1489,15 +1502,13 @@ code .dim {
}
@media (prefers-color-scheme: dark) {
#homepage-repl-container .color-white {
color: #FFF;
color: #fff;
}
#repl-container .color-white {
color: #FFF;
color: #fff;
}
}
.bold {