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: This roc file can print its own source code. The source is:
app "ingested-file" 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 [ imports [
pf.Stdout, pf.Stdout,
pf.Task,
"ingested-file.roc" as ownCode : Str, "ingested-file.roc" as ownCode : Str,
] ]
provides [main] to pf provides [main] to pf
main = 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!( indoc!(
r#" r#"
app "helloWorld" 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] imports [pf.Stdout]
provides [main] to pf provides [main] to pf

View file

@ -1,7 +1,7 @@
app "hello" app "hello"
packages { packages {
pf: 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] imports [pf.Stdout]
provides [main] to pf provides [main] to pf

View file

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

View file

@ -1,6 +1,6 @@
app "hello" app "hello"
packages { pf: 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] imports [pf.Stdout]
provides [main] to pf provides [main] to pf

View file

@ -74,7 +74,8 @@ impl Registry {
if &document.doc_info.url == updating_url { 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 //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) { 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 log::{debug, trace};
use registry::{Registry, RegistryConfig}; use registry::{Registry, RegistryConfig};
use std::future::Future; use std::future::Future;
use std::panic::AssertUnwindSafe; use std::panic::{catch_unwind, AssertUnwindSafe};
use std::time::Duration; use std::time::Duration;
use tower_lsp::jsonrpc::{self, Result}; use tower_lsp::jsonrpc::{self, Result};
@ -173,9 +173,24 @@ impl RocServerState {
return Err("Not latest version skipping analysis".to_string()); return Err("Not latest version skipping analysis".to_string());
} }
let results = match tokio::task::spawn_blocking(|| global_analysis(doc_info)).await { let results = match tokio::time::timeout(
Err(e) => return Err(format!("Document analysis failed. reason:{:?}", e)), Duration::from_secs(60),
Ok(a) => a, 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; 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, // 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. // so here we assume the only change passed is a change of the entire document's content.
let TextDocumentContentChangeEvent { text, .. } = let TextDocumentContentChangeEvent { text, .. } = params
params.content_changes.into_iter().next().unwrap(); .content_changes
.into_iter()
.last()
.expect("textDocument change event had no changes ");
self.change(uri, text, version).await; self.change(uri, text, version).await;
} }

View file

@ -1,11 +1,10 @@
app "args" 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 }] imports [pf.Stdout, pf.Arg, pf.Task.{ Task }]
provides [main] to pf provides [main] to pf
main : Task {} I32
main = main =
args <- Arg.list |> Task.await args = Arg.list!
parser = parser =
divCmd = divCmd =
Arg.succeed (\dividend -> \divisor -> Div (Num.toF64 dividend) (Num.toF64 divisor)) Arg.succeed (\dividend -> \divisor -> Div (Num.toF64 dividend) (Num.toF64 divisor))
@ -55,13 +54,12 @@ main =
|> Num.toStr |> Num.toStr
|> Stdout.line |> Stdout.line
Err helpMenu -> Err helpMenuErr ->
{} <- Stdout.line helpMenu |> Task.await Task.err (Exit 1 "unable to parse args: $(Inspect.toStr helpMenuErr)")
Task.err 1
runCmd = \cmd -> runCmd = \cmd ->
when cmd is when cmd is
Div n d -> n / d Div n d -> n / d
Log b n -> Log b n ->
# log_b(n) = log_x(n) / log_x(b) for all x # log_b(n) = log_x(n) / log_x(b) for all x
runCmd (Div (Num.log n) (Num.log b)) runCmd (Div (Num.log n) (Num.log b))

View file

@ -1,5 +1,5 @@
app "countdown" 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 }] imports [pf.Stdin, pf.Stdout, pf.Task.{ await, loop }]
provides [main] to pf provides [main] to pf

View file

@ -1,21 +1,19 @@
app "echo" 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 }] imports [pf.Stdin, pf.Stdout, pf.Task.{ Task }]
provides [main] to pf provides [main] to pf
main : Task {} I32
main = main =
_ <- Task.await (Stdout.line "🗣 Shout into this cave and hear the echo! 👂👂👂") _ <- Task.await (Stdout.line "🗣 Shout into this cave and hear the echo! 👂👂👂")
Task.loop {} tick Task.loop {} tick
tick : {} -> Task [Step {}, Done {}] * tick : {} -> Task [Step {}, Done {}] _
tick = \{} -> tick = \{} ->
shout <- Task.await Stdin.line when Stdin.line |> Task.result! is
Ok str -> Stdout.line (echo str) |> Task.map Step
when shout is Err (StdinErr EndOfFile) -> Stdout.line (echo "Received end of input (EOF).") |> Task.map Done
Input s -> Stdout.line (echo s) |> Task.map Step Err (StdinErr err) -> Stdout.line (echo "Unable to read input $(Inspect.toStr err)") |> Task.map Done
End -> Stdout.line (echo "Received end of input (EOF).") |> Task.map Done
echo : Str -> Str echo : Str -> Str
echo = \shout -> echo = \shout ->

View file

@ -1,9 +1,8 @@
app "env" 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 }] imports [pf.Stdout, pf.Stderr, pf.Env, pf.Task.{ Task }]
provides [main] to pf provides [main] to pf
main : Task {} I32
main = main =
task = task =
Env.decode "EDITOR" Env.decode "EDITOR"

View file

@ -1,8 +1,7 @@
app "file-io" 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 [ imports [
pf.Stdout, pf.Stdout,
pf.Stderr,
pf.Task.{ Task }, pf.Task.{ Task },
pf.File, pf.File,
pf.Path, pf.Path,
@ -11,34 +10,30 @@ app "file-io"
] ]
provides [main] to pf provides [main] to pf
main : Task {} I32 main : Task {} [Exit I32 Str]_
main = main =
path = Path.fromStr "out.txt" path = Path.fromStr "out.txt"
task = task =
cwd <- Env.cwd |> Task.await cwd = Env.cwd!
cwdStr = Path.display cwd Stdout.line! "cwd: $(Path.display cwd)"
dirEntries = Dir.list! cwd
_ <- Stdout.line "cwd: $(cwdStr)" |> Task.await
dirEntries <- Dir.list cwd |> Task.await
contentsStr = Str.joinWith (List.map dirEntries Path.display) "\n " 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 when Task.result! task is
_ <- Stdout.line "Writing a string to out.txt" |> Task.await Ok {} -> Stdout.line! "Successfully wrote a string to out.txt"
_ <- File.writeUtf8 path "a string!" |> Task.await Err err ->
contents <- File.readUtf8 path |> Task.await msg =
Stdout.line "I read the file back. Its contents: \"$(contents)\"" when err is
FileWriteErr _ PermissionDenied -> "PermissionDenied"
FileWriteErr _ Unsupported -> "Unsupported"
FileWriteErr _ (Unrecognized _ other) -> other
FileReadErr _ _ -> "Error reading file"
_ -> "Uh oh, there was an error!"
Task.attempt task \result -> Task.err (Exit 1 msg)
when result is
Ok {} -> Stdout.line "Successfully wrote a string to out.txt"
Err err ->
msg =
when err is
FileWriteErr _ PermissionDenied -> "PermissionDenied"
FileWriteErr _ Unsupported -> "Unsupported"
FileWriteErr _ (Unrecognized _ other) -> other
FileReadErr _ _ -> "Error reading file"
_ -> "Uh oh, there was an error!"
{} <- Stderr.line msg |> Task.await
Task.err 1

View file

@ -1,20 +1,12 @@
app "form" app "form"
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, Task }] imports [pf.Stdin, pf.Stdout, pf.Task]
provides [main] to pf provides [main] to pf
main : Task {} I32
main = main =
_ <- await (Stdout.line "What's your first name?") Stdout.line! "What's your first name?"
firstName <- await Stdin.line firstName = Stdin.line!
Stdout.line! "What's your last name?"
lastName = Stdin.line!
_ <- await (Stdout.line "What's your last name?") Stdout.line "Hi, $(firstName) $(lastName)! 👋"
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)."

View file

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

View file

@ -1,7 +1,8 @@
app "ingested-file-bytes" 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 [ imports [
pf.Stdout, pf.Stdout,
pf.Task,
"../../LICENSE" as license : _, # A type hole can also be used here. "../../LICENSE" as license : _, # A type hole can also be used here.
] ]
provides [main] to pf provides [main] to pf
@ -9,7 +10,7 @@ app "ingested-file-bytes"
main = main =
# Due to how license is used, it will be a List U8. # Due to how license is used, it will be a List U8.
license license
|> List.map Num.toU64 |> List.map Num.toU64
|> List.sum |> List.sum
|> Num.toStr |> Num.toStr
|> Stdout.line |> Stdout.line!

View file

@ -1,10 +1,11 @@
app "ingested-file" 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 [ imports [
pf.Stdout, pf.Stdout,
pf.Task,
"ingested-file.roc" as ownCode : Str, "ingested-file.roc" as ownCode : Str,
] ]
provides [main] to pf provides [main] to pf
main = 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" 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] imports [pf.Stdout, pf.Task]
provides [main] to pf provides [main] to pf
main = main =
Stdout.line "Hello, World!" Stdout.line! "Hello, World!"

View file

@ -2,37 +2,38 @@
# Shows how Roc values can be logged # Shows how Roc values can be logged
# #
app "inspect-logging" 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 [ imports [
pf.Stdout, pf.Stdout,
pf.Task,
Community, Community,
] ]
provides [main] to pf provides [main] to pf
main = main =
Community.empty Community.empty
|> Community.addPerson { |> Community.addPerson {
firstName: "John", firstName: "John",
lastName: "Smith", lastName: "Smith",
age: 27, age: 27,
hasBeard: Bool.true, hasBeard: Bool.true,
favoriteColor: Blue, favoriteColor: Blue,
} }
|> Community.addPerson { |> Community.addPerson {
firstName: "Debby", firstName: "Debby",
lastName: "Johnson", lastName: "Johnson",
age: 47, age: 47,
hasBeard: Bool.false, hasBeard: Bool.false,
favoriteColor: Green, favoriteColor: Green,
} }
|> Community.addPerson { |> Community.addPerson {
firstName: "Jane", firstName: "Jane",
lastName: "Doe", lastName: "Doe",
age: 33, age: 33,
hasBeard: Bool.false, hasBeard: Bool.false,
favoriteColor: RGB (255, 255, 0), favoriteColor: RGB (255, 255, 0),
} }
|> Community.addFriend 0 2 |> Community.addFriend 0 2
|> Community.addFriend 1 2 |> Community.addFriend 1 2
|> Inspect.toStr |> Inspect.toStr
|> Stdout.line |> Stdout.line!

View file

@ -1,11 +1,12 @@
app "example" app "example"
packages { 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", parser: "https://github.com/lukewilliamboswell/roc-parser/releases/download/0.5.2/9VrPjwfQQ1QeSL3CfmWr2Pr9DESdDIXy97pwpuq84Ck.tar.br",
} }
imports [ imports [
cli.Stdout, cli.Stdout,
cli.Stderr, cli.Stderr,
cli.Task,
parser.Core.{ Parser, buildPrimitiveParser, many }, parser.Core.{ Parser, buildPrimitiveParser, many },
parser.String.{ parseStr }, parser.String.{ parseStr },
] ]

View file

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

View file

@ -155,8 +155,8 @@ Make a file named `main.roc` and put this in it:
```roc ```roc
app "hello" 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] imports [pf.Stdout, pf.Task]
provides [main] to pf provides [main] to pf
main = main =
@ -1455,7 +1455,7 @@ Let's take a closer look at the part of `main.roc` above the `main` def:
```roc ```roc
app "hello" 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] imports [pf.Stdout]
provides [main] to pf 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: The remaining lines all involve the [platform](https://github.com/roc-lang/roc/wiki/Roc-concepts-explained#platform) this application is built on:
```roc ```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] imports [pf.Stdout]
provides [main] to pf provides [main] to pf
``` ```
@ -1566,7 +1566,7 @@ Let's start with a basic "Hello World" program.
```roc ```roc
app "cli-tutorial" 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] imports [pf.Stdout]
provides [main] to pf 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 ```roc
app "cli-tutorial" 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] imports [pf.Stdout, pf.Stdin, pf.Task]
provides [main] to pf 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: If we wanted to add the type annotation to `main` that Roc is inferring for it, we would add this annotation:
```roc ```roc
main : Task {} [Exit I32, StdoutErr Stdout.Err, StinErr Stdin.Err] main : Task {} [Exit I32, StdoutErr Stdout.Err, StdinErr Stdin.Err]
main = 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. - `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.) - `{}` 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 To understand what the `Exit I32 Str` error means, let's try temporarily commenting out our current `main` and replacing
it with this one: it with this one:
@ -1666,7 +1666,7 @@ In summary:
### [Handling task failures](#handling-task-failures) {#handling-task-failures} ### [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: 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-color: #1bbcb3;
--header-link-hover: #222; --header-link-hover: #222;
--h1-color: #8055e4; --h1-color: #8055e4;
--tutorial-h3-color: #8c5ce3; /* Slightly darker than --primary-1, which looks washed-out in <h3>s */
} }
html { html {
@ -167,7 +168,7 @@ hr {
} }
#sponsor-logos .logo-decem .cls-1 { #sponsor-logos .logo-decem .cls-1 {
fill:#04021e; fill: #04021e;
} }
#sponsor-logos + p { #sponsor-logos + p {
@ -731,7 +732,8 @@ li {
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-display: swap; 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"), format("woff2"),
url("/fonts/permanent-marker-v16-latin/permanent-marker-v16-latin-regular.woff") url("/fonts/permanent-marker-v16-latin/permanent-marker-v16-latin-regular.woff")
format("woff"); format("woff");
@ -746,7 +748,8 @@ li {
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-display: swap; 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"), format("woff2"),
url("/fonts/lato-v23-latin-ext_latin/lato-v23-latin-ext_latin-regular.woff") url("/fonts/lato-v23-latin-ext_latin/lato-v23-latin-ext_latin-regular.woff")
format("woff"); format("woff");
@ -760,7 +763,8 @@ li {
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-display: swap; 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"), format("woff2"),
url("/fonts/lato-v23-latin/lato-v23-latin-regular.woff") format("woff"); 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, 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-style: normal;
font-weight: 400; font-weight: 400;
font-display: swap; 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"), format("woff2"),
url("/fonts/source-code-pro-v22-latin-ext_latin/source-code-pro-v22-latin-ext_latin-regular.woff") url("/fonts/source-code-pro-v22-latin-ext_latin/source-code-pro-v22-latin-ext_latin-regular.woff")
format("woff"); format("woff");
@ -788,7 +793,8 @@ li {
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-display: swap; 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"), format("woff2"),
url("/fonts/source-code-pro-v22-latin/source-code-pro-v22-latin-regular.woff") url("/fonts/source-code-pro-v22-latin/source-code-pro-v22-latin-regular.woff")
format("woff"); format("woff");
@ -825,6 +831,7 @@ li {
--header-link-color: #9c7cea; --header-link-color: #9c7cea;
--header-link-hover: #ddd; --header-link-hover: #ddd;
--h1-color: #1bc6bd; --h1-color: #1bc6bd;
--tutorial-h3-color: var(--primary-1);
} }
.logo-dark { .logo-dark {
@ -1137,7 +1144,8 @@ code .dim {
color: #7c38f5; color: #7c38f5;
} }
.interactive-desc code, .interactive-desc pre { .interactive-desc code,
.interactive-desc pre {
background: none; background: none;
color: inherit; color: inherit;
} }
@ -1201,9 +1209,12 @@ code .dim {
border: none; border: none;
} }
#tutorial-main h3 a {
color: var(--tutorial-h3-color);
}
#tutorial-main h1 a, #tutorial-main h1 a,
#tutorial-main h2 a, #tutorial-main h2 a,
#tutorial-main h3 a,
#tutorial-main h4 a, #tutorial-main h4 a,
#tutorial-main h5 a { #tutorial-main h5 a {
color: var(--header-link-color); color: var(--header-link-color);
@ -1240,7 +1251,7 @@ code .dim {
font-family: inherit; font-family: inherit;
font-size: 1.65rem; font-size: 1.65rem;
line-height: 3rem; line-height: 3rem;
text-shadow: 1px 1px 1px #010101; margin-bottom: 0.5rem;
} }
#tutorial-main h4 { #tutorial-main h4 {
@ -1364,12 +1375,14 @@ code .dim {
font-size: 18px; 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; top: 1.25rem;
color: var(--light-cyan); color: var(--light-cyan);
} }
.input-line-prefix, #repl-prompt { .input-line-prefix,
#repl-prompt {
color: var(--cyan); color: var(--cyan);
color: var(--primary-2); 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! in a light color scheme, and only white in dark mode. The name could be better!
*/ */
#homepage-repl-container .color-white { #homepage-repl-container .color-white {
color: #FFF; color: #fff;
} }
#repl-container .color-white { #repl-container .color-white {
@ -1489,15 +1502,13 @@ code .dim {
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
#homepage-repl-container .color-white { #homepage-repl-container .color-white {
color: #FFF; color: #fff;
} }
#repl-container .color-white { #repl-container .color-white {
color: #FFF; color: #fff;
} }
} }
.bold { .bold {