From 0cafe74e4a85a5b54a0a394e49802af5f19b7b17 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Sun, 17 Mar 2024 12:27:28 -0500 Subject: [PATCH] updated: examples page --- examples | 1 + src/app.onyx | 188 +----------------------------- src/resources.onyx | 87 ++++++++++++++ src/static_routes.onyx | 127 ++++++++++++++++++++ www/examples/fib.html | 118 ++++++++++++++++++- www/examples/fib.onyx | 113 ------------------ www/examples/files.html | 82 ++++++++++++- www/examples/files.onyx | 76 ------------ www/examples/index.json | 20 +--- www/examples/stdin.html | 40 ++++++- www/examples/stdin.onyx | 36 ------ www/packages/core_packages.json | 5 + www/static/css/new_style.css | 30 ++++- www/templates/pages/example.html | 34 ++++++ www/templates/pages/examples.html | 29 +++-- 15 files changed, 536 insertions(+), 450 deletions(-) create mode 160000 examples create mode 100644 src/resources.onyx create mode 100644 src/static_routes.onyx delete mode 100644 www/examples/fib.onyx delete mode 100644 www/examples/files.onyx delete mode 100644 www/examples/stdin.onyx create mode 100644 www/templates/pages/example.html diff --git a/examples b/examples new file mode 160000 index 0000000..1df16a3 --- /dev/null +++ b/examples @@ -0,0 +1 @@ +Subproject commit 1df16a331e64f15a5095d2e79dbc2dcece461382 diff --git a/src/app.onyx b/src/app.onyx index 3cf8497..0273192 100644 --- a/src/app.onyx +++ b/src/app.onyx @@ -29,114 +29,6 @@ reg: otmp.TemplateRegistry; } } -@route.{.GET, "/"} -(req: &Req, res: &Res) { - articles := iter.as_iter(news_articles->get() ?? .[])->take(2)->collect(); - res->render("pages/homepage", &.{ articles = articles }); -} - -@route.{.GET, "/ovmwasm"} -(req: &Req, res: &Res) => res->render("pages/ovmwasm", null); - -@route.{.GET, "/docs"} -(req: &Req, res: &Res) => res->render("pages/docs", null); - -@route.{.GET, "/docs/install"} -(req: &Req, res: &Res) => res->render("pages/docs/install", null); - -@route.{.GET, "/docs/setup"} -(req: &Req, res: &Res) => res->render("pages/docs/env_setup", null); - -@route.{.GET, "/docs/getting_started"} -(req: &Req, res: &Res) => res->render("pages/docs/getting_started", null); - -@route.{.GET, "/docs/guides"} -(req: &Req, res: &Res) => res->render("pages/docs/guides", null); - -@route.{.GET, "/docs/guides/http-server"} -(req: &Req, res: &Res) => res->render("pages/docs/guide_http_server", null); - -@route.{.GET, "/docs/guides/raylib"} -(req: &Req, res: &Res) => res->render("pages/docs/guide_raylib", null); - -@route.{.GET, "/docs/packages"} -(req: &Req, res: &Res) => res->render("pages/docs/package", null); - -@route.{.GET, "/docs/packages/list"} -(req: &Req, res: &Res) { - res->render("pages/docs/package_list", &.{ - core_packages = core_packages, - third_party_packages = third_party_packages - }); -} - -@route.{.GET, "/playground"} -(req: &Req, res: &Res) { - res->body("text/html", "This has been moved to try.onyxlang.io."); - res->status(200); - res->end(); -} - -@route.{.GET, "/community"} -(req: &Req, res: &Res) => res->render("pages/community", null); - - -@route.{.GET, "/robots.txt"} -(req: &Req, res: &Res) { - res->file("./www/static/robots.txt"); - res->status(200); - res->end(); -} - - -Article :: struct { name, description, path, date: str } -news_articles: Cached_Resource([] Article); - -@route.{.GET, "/news/:article"} -(req: &Req, res: &Res) { - article_path := req.url_params["article"] ?? ""; - article := array.first(news_articles->get() ?? .[], [n](n.path == article_path)); - if !article { - res->render("pages/404", null); - res->status(404); - return; - } - - filename := tprintf("www/news-articles/{}.html", article.path); - - if os.file_exists(filename) { - contents := os.get_contents(filename); - defer delete(&contents); - - res->render("pages/news_article", &.{ - article = .{ contents = contents, name = article.name, description = article.description } - }); - - } else { - res->render("pages/404", null); - res->status(404); - return; - } -} - -@route.{.GET, "/news"} -(req: &Req, res: &Res) { - articles := news_articles->get() ?? .[]; - - res->render("pages/news", &.{ - articles = articles - }); -} - -@route.{.GET, "/examples"} -(req: &Req, res: &Res) { - exs := examples->get() ?? .[]; - - res->render("pages/examples", &.{ - examples = exs - }); -} - main :: () { default_log_level(.Error); load_library_list(); @@ -148,24 +40,8 @@ main :: () { resource = .{}, max_age = 60 * 60, // 1 hour - fetch_resource = () -> ? [] Article { - article_file := os.get_contents("www/news-articles/index.json"); - article_index, json_err := json.decode_with_error(article_file); - if json_err->has_error() { - return .{}; - } - - articles: [] Article; - #context_scope { - context.allocator = alloc.heap_allocator; - json.as_any(article_index.root, &articles); - } - return articles; - }, - - release_resource = (articles: &[] Article) { - delete(articles, allocator=alloc.heap_allocator); - } + fetch_resource = fetch_articles, + release_resource = release_articles }; examples = .{ @@ -221,63 +97,3 @@ main :: () { } } - -Package :: struct { - url, name, description: str; -} - -Example :: struct { - name, code, html: str; -} - -#local { - core_packages: [] Package; - third_party_packages: [] Package; - - examples: Cached_Resource([] Example); -} - -load_library_list :: () { - os.get_contents("www/packages/core_packages.json") - |> json.decode_into(&core_packages); - - slice.sort(core_packages, (a, b) => string.compare(a.name, b.name)); - - os.get_contents("www/packages/third_party_packages.json") - |> json.decode_into(&third_party_packages); - - slice.sort(third_party_packages, (a, b) => string.compare(a.name, b.name)); -} - -load_examples :: () -> ? [] Example { - #context_scope { - context.allocator = alloc.heap_allocator; - - examples: [] Example; - - os.get_contents("www/examples/index.json") - |> json.decode_into(&examples); - - for &example in examples { - code_path := os.path_join("www/examples", example.code); - html_path := os.path_join("www/examples", example.html); - - example.code = os.get_contents(code_path); - example.html = os.get_contents(html_path); - } - - return examples; - } -} - -delete_examples :: (exs: &[] Example) do #context_scope { - context.allocator = alloc.heap_allocator; - - for &ex in *exs { - delete(&ex.code); - delete(&ex.html); - } - - delete(exs); -} - diff --git a/src/resources.onyx b/src/resources.onyx new file mode 100644 index 0000000..bb5302a --- /dev/null +++ b/src/resources.onyx @@ -0,0 +1,87 @@ +use core.alloc +use core.string +use core.encoding.json +use core.os +use core.slice +use core { + tprintf +} + +Package :: struct { + url, name, description: str; +} + +Example :: struct { + title, name, description, author, html: str; + tags: [] str; +} + +core_packages: [] Package; +third_party_packages: [] Package; + +examples: Cached_Resource([] Example); + + + +load_library_list :: () { + os.get_contents("www/packages/core_packages.json") + |> json.decode_into(&core_packages); + + slice.sort(core_packages, (a, b) => string.compare(a.name, b.name)); + + os.get_contents("www/packages/third_party_packages.json") + |> json.decode_into(&third_party_packages); + + slice.sort(third_party_packages, (a, b) => string.compare(a.name, b.name)); +} + +load_examples :: () -> ? [] Example { + #context_scope { + context.allocator = alloc.heap_allocator; + + examples: struct { list: [..] Example }; + + os.get_contents("www/examples/index.json") + |> json.decode_into(&examples); + + for &example in examples.list { + code_path := os.path_join("www/examples", tprintf("{}.html", example.name)); + example.html = os.get_contents(code_path); + } + + return examples.list; + } +} + +delete_examples :: (exs: &[] Example) do #context_scope { + context.allocator = alloc.heap_allocator; + + for &ex in *exs { + delete(&ex.html); + } + + delete(exs); +} + + +Article :: struct { name, description, path, date: str } +news_articles: Cached_Resource([] Article); + +fetch_articles :: () -> ? [] Article { + article_file := os.get_contents("www/news-articles/index.json"); + article_index, json_err := json.decode_with_error(article_file); + if json_err->has_error() { + return .{}; + } + + articles: [] Article; + #context_scope { + context.allocator = alloc.heap_allocator; + json.as_any(article_index.root, &articles); + } + return articles; +} + +release_articles :: (articles: &[] Article) { + delete(articles, allocator=alloc.heap_allocator); +} diff --git a/src/static_routes.onyx b/src/static_routes.onyx new file mode 100644 index 0000000..87a62b7 --- /dev/null +++ b/src/static_routes.onyx @@ -0,0 +1,127 @@ +use core {package, *} +use runtime +use otmp +use http +use http.server {Req :: Request, Res :: Response, route} +use core.encoding.json + + +@route.{.GET, "/"} +(req: &Req, res: &Res) { + articles := iter.as_iter(news_articles->get() ?? .[])->take(2)->collect(); + res->render("pages/homepage", &.{ articles = articles }); +} + +@route.{.GET, "/ovmwasm"} +(req: &Req, res: &Res) => res->render("pages/ovmwasm", null); + +@route.{.GET, "/docs"} +(req: &Req, res: &Res) => res->render("pages/docs", null); + +@route.{.GET, "/docs/install"} +(req: &Req, res: &Res) => res->render("pages/docs/install", null); + +@route.{.GET, "/docs/setup"} +(req: &Req, res: &Res) => res->render("pages/docs/env_setup", null); + +@route.{.GET, "/docs/getting_started"} +(req: &Req, res: &Res) => res->render("pages/docs/getting_started", null); + +@route.{.GET, "/docs/guides"} +(req: &Req, res: &Res) => res->render("pages/docs/guides", null); + +@route.{.GET, "/docs/guides/http-server"} +(req: &Req, res: &Res) => res->render("pages/docs/guide_http_server", null); + +@route.{.GET, "/docs/guides/raylib"} +(req: &Req, res: &Res) => res->render("pages/docs/guide_raylib", null); + +@route.{.GET, "/docs/packages"} +(req: &Req, res: &Res) => res->render("pages/docs/package", null); + +@route.{.GET, "/docs/packages/list"} +(req: &Req, res: &Res) { + res->render("pages/docs/package_list", &.{ + core_packages = core_packages, + third_party_packages = third_party_packages + }); +} + +@route.{.GET, "/playground"} +(req: &Req, res: &Res) { + res->body("text/html", "This has been moved to try.onyxlang.io."); + res->status(200); + res->end(); +} + +@route.{.GET, "/community"} +(req: &Req, res: &Res) => res->render("pages/community", null); + + +@route.{.GET, "/robots.txt"} +(req: &Req, res: &Res) { + res->file("./www/static/robots.txt"); + res->status(200); + res->end(); +} + + + +@route.{.GET, "/news/:article"} +(req: &Req, res: &Res) { + article_path := req.url_params["article"] ?? ""; + article := array.first(news_articles->get() ?? .[], [n](n.path == article_path)); + if !article { + res->render("pages/404", null); + res->status(404); + return; + } + + filename := tprintf("www/news-articles/{}.html", article.path); + + if os.file_exists(filename) { + contents := os.get_contents(filename); + defer delete(&contents); + + res->render("pages/news_article", &.{ + article = .{ contents = contents, name = article.name, description = article.description } + }); + + } else { + res->render("pages/404", null); + res->status(404); + return; + } +} + +@route.{.GET, "/news"} +(req: &Req, res: &Res) { + articles := news_articles->get() ?? .[]; + + res->render("pages/news", &.{ + articles = articles + }); +} + +@route.{.GET, "/examples"} +(req: &Req, res: &Res) { + exs := examples->get() ?? .[]; + + res->render("pages/examples", &.{ + examples = exs + }); +} + +@route.{.GET, "/examples/:name"} +(req: &Req, res: &Res) { + exs := examples->get() ?? .[]; + name := req.url_params["name"] ?? ""; + + ex := slice.first(exs, [x](x.name == name)); + + res->render("pages/example", &.{ + ex = ex + }); +} + + diff --git a/www/examples/fib.html b/www/examples/fib.html index 8a0aace..e4a6959 100644 --- a/www/examples/fib.html +++ b/www/examples/fib.html @@ -1,3 +1,115 @@ -

- This example shows three different ways to do the same thing: compute Fibonacci numbers. -

+

Fibonacci Sequence

+

Brendan Hansen

+
This example shows three different ways to do the same thing: compute Fibonacci numbers.
+
use core.iter
+use core { printf }
+
+//
+// Way number 1: A simple for-loop
+// This method simply uses a for-loop like you would in C to generate
+// the Fibonacci numbers. No tricks to it.
+//
+fib_for_loop :: (n: i32) -> u64 {
+    a: u64 = 0;
+    b: u64 = 1;
+
+    for 0 .. n {
+        tmp := a;
+        a = b;
+        b = tmp + b;
+    }
+
+    return a;
+}
+
+//
+// Way number 2: Functional folding
+// This way creates an iterator that will yield n integers, thats the
+// iter.counter piped to iter.take(n). Then, for each one of those numbers
+// it steps the state, computing the Fibonacci numbers in the process.
+// The final result is the "a" member of the final state.
+
+FibState :: struct { a, b: u64 }
+
+fib_by_fold :: (n: i32) => {
+    end_state := 
+        // This creates an infinite iterator that simply counts up from 0.
+        iter.counter()
+
+        // This limits only taking the first n values.
+        |> iter.take(n)
+
+        // This performs a "fold" or "reduce" operation.
+        |> iter.fold(
+            // This defines the initial accumulator state.
+            FibState.{ a = 0, b = 1 },
+
+            // This defines the "folding" function. It takes the next value
+            // from the iterator, which we simply ignore because we do not
+            // need it, and the previous value of the accumulator. It then
+            // computes and returns the next value for the accumulator.
+            // iter.fold returns the final value of the accumulator.
+            (_, state) => FibState.{
+                a = state.b,
+                b = state.a + state.b
+            }
+        );
+
+    return end_state.a;
+}
+
+
+//
+// Way number 3: A custom iterator
+// This way produces an iterator that yields consecutive Fibonacci numbers.
+// This is slightly faster than the previous methods because it does not have
+// to redo all the work for every query.
+//
+
+fib_iterator :: (n: i32) => 
+    // This is implemented using a generator, which is a custom iterator
+    // that yields values according to the "next" function defined below.
+    iter.generator(
+        // The initial state of the generator.
+        &.{ a = cast(u64) 0, b = cast(u64) 1, counter = n },
+
+        // The generation function. This takes in a pointer to the state
+        // and must return 2 things: the next value and a boolean of whether
+        // to continue or not.
+        // 
+        // Notice that the parameter's type is a polymorphic here; notice the $.
+        // This is because the above structure literal is entirely type infered;
+        // no explicit type was given to it. Therefore, there is no type we can
+        // write here that would be correct. We could make a structure for it,
+        // but in this case it is fine to let the compiler do a little magic.
+        (state: & $Ctx) -> (u64, bool) {
+            if state.counter <= 0 {
+                return 0, false;
+            }
+
+            tmp := state.a;
+            state.a = state.b;
+            state.b = state.b + tmp;
+
+            state.counter -= 1;
+            return tmp, true;
+        }
+    );
+
+
+main :: () {
+    // Print the results from fib_for_loop
+    for i in 0 .. 90 {
+        printf("{}: {}\n", i, fib_for_loop(i));
+    }
+
+    // Print the results from fib_by_fold
+    for i in 0 .. 90 {
+        printf("{}: {}\n", i, fib_by_fold(i));
+    }
+
+    // Print the results from fib_iterator
+    for value, index in fib_iterator(90) {
+        printf("{}: {}\n", index, value);
+    }
+}
diff --git a/www/examples/fib.onyx b/www/examples/fib.onyx deleted file mode 100644 index dd21612..0000000 --- a/www/examples/fib.onyx +++ /dev/null @@ -1,113 +0,0 @@ -use core.iter -use core { printf } - -// -// Way number 1: A simple for-loop -// This method simply uses a for-loop like you would in C to generate -// the Fibonacci numbers. No tricks to it. -// -fib_for_loop :: (n: i32) -> u64 { - a: u64 = 0; - b: u64 = 1; - - for 0 .. n { - tmp := a; - a = b; - b = tmp + b; - } - - return a; -} - -// -// Way number 2: Functional folding -// This way creates an iterator that will yield n integers, thats the -// iter.counter piped to iter.take(n). Then, for each one of those numbers -// it steps the state, computing the Fibonacci numbers in the process. -// The final result is the "a" member of the final state. - -FibState :: struct { a, b: u64 } - -fib_by_fold :: (n: i32) => { - end_state := - // This creates an infinite iterator that simply counts up from 0. - iter.counter() - - // This limits only taking the first n values. - |> iter.take(n) - - // This performs a "fold" or "reduce" operation. - |> iter.fold( - // This defines the initial accumulator state. - FibState.{ a = 0, b = 1 }, - - // This defines the "folding" function. It takes the next value - // from the iterator, which we simply ignore because we do not - // need it, and the previous value of the accumulator. It then - // computes and returns the next value for the accumulator. - // iter.fold returns the final value of the accumulator. - (_, state) => FibState.{ - a = state.b, - b = state.a + state.b - } - ); - - return end_state.a; -} - - -// -// Way number 3: A custom iterator -// This way produces an iterator that yields consecutive Fibonacci numbers. -// This is slightly faster than the previous methods because it does not have -// to redo all the work for every query. -// - -fib_iterator :: (n: i32) => - // This is implemented using a generator, which is a custom iterator - // that yields values according to the "next" function defined below. - iter.generator( - // The initial state of the generator. - &.{ a = cast(u64) 0, b = cast(u64) 1, counter = n }, - - // The generation function. This takes in a pointer to the state - // and must return 2 things: the next value and a boolean of whether - // to continue or not. - // - // Notice that the parameter's type is a polymorphic here; notice the $. - // This is because the above structure literal is entirely type infered; - // no explicit type was given to it. Therefore, there is no type we can - // write here that would be correct. We could make a structure for it, - // but in this case it is fine to let the compiler do a little magic. - (state: & $Ctx) -> (u64, bool) { - if state.counter <= 0 { - return 0, false; - } - - tmp := state.a; - state.a = state.b; - state.b = state.b + tmp; - - state.counter -= 1; - return tmp, true; - } - ); - - -main :: () { - // Print the results from fib_for_loop - for i in 0 .. 90 { - printf("{}: {}\n", i, fib_for_loop(i)); - } - - // Print the results from fib_by_fold - for i in 0 .. 90 { - printf("{}: {}\n", i, fib_by_fold(i)); - } - - // Print the results from fib_iterator - for value, index in fib_iterator(90) { - printf("{}: {}\n", index, value); - } -} - diff --git a/www/examples/files.html b/www/examples/files.html index dc80a3f..1f54a50 100644 --- a/www/examples/files.html +++ b/www/examples/files.html @@ -1,4 +1,78 @@ -

- This example shows various ways of reading and writing to a file. - The core idea behind files in Onyx is that they extend the io.Stream structure, so you can use the core.io package to interact with them. -

+

File Operations

+

Brendan Hansen

+
This example shows various ways of reading and writing to a file. The core idea behind files in Onyx is that they extend the io.Stream structure, so you can use the core.io package to interact with them.
+
use core.os
+use core.io
+use core.string
+use core {
+    printf
+}
+
+#doc "Writes example text into a file."
+write_data_into_file :: (filename: str) {
+    // This is one way of opening a file: call os.open and then os.close later.
+    // os.open returns a Result(os.File, os.FileError), so it must be handled
+    // to use the os.File. This program opts to unwrap the result.
+    file := os.open(filename, .Write)->unwrap();
+    defer os.close(&file);
+
+    // Create an io.Writer over the file stream using io.writer_make.
+    // Also, free it later by defering io.writer_free. This also flushes
+    // the internal buffer of io.Writer to make sure everything is written
+    // to the file.
+    file_writer := io.writer_make(&file);
+    defer io.writer_free(&file_writer);
+
+    // The simplest way of writing a string to the file.
+    io.write(&file_writer, "This is the first line of text.\n");
+
+    // io.write_format can be used to "printf" into a file.
+    // printf can be thought of as io.write_format(&stdio.stream, ...).
+    io.write_format(&file_writer, "This is a {} line of text.\n", "formatted");
+
+    for i in 0 .. 5 {
+        io.write_format(&file_writer, "Another line numbered {}.\n", i);
+    }
+}
+
+#doc "Reads example text from a file."
+read_data_from_file :: (filename: str) {
+    // This is another way of opening a file. Because of the semantics
+    // of `for` loops over Iterators, they can behave like `with`
+    // statements in Python or `using` statements in C#.
+    for file in os.with_file(filename, .Read) {
+        // Create a io.Reader over the file stream.
+        file_reader := io.reader_make(file);
+        defer io.reader_free(&file_reader);
+
+        // Read a single line.
+        first_line := io.read_line(&file_reader);
+        printf("First line: {}\n", first_line);
+
+        // Use io.lines to create an iterator over the remaining
+        // lines in the file.
+        printf("Remaining lines:\n");
+        for line, index in io.lines(&file_reader) {
+            printf("{}: {}\n", index, line);
+        }
+    }
+}
+
+#doc "Reads example text from a file."
+read_whole_file :: (filename: str) {
+    // This is the simplest way to get the entire content of a file
+    // into a string ([] u8). Also, defer "deleting" the string, which
+    // will free the memory allocated for the string.
+    contents := os.get_contents(filename);
+    defer delete(&contents);
+
+    printf("Whole contents:\n{}\n", contents);
+}
+
+main :: () {
+    filename := "test.txt";
+
+    write_data_into_file(filename);
+    read_data_from_file(filename);
+    read_whole_file(filename);
+}
diff --git a/www/examples/files.onyx b/www/examples/files.onyx deleted file mode 100644 index b216796..0000000 --- a/www/examples/files.onyx +++ /dev/null @@ -1,76 +0,0 @@ -use core.os -use core.io -use core.string -use core { - printf -} - -#doc "Writes example text into a file." -write_data_into_file :: (filename: str) { - // This is one way of opening a file: call os.open and then os.close later. - // os.open returns a Result(os.File, os.FileError), so it must be handled - // to use the os.File. This program opts to unwrap the result. - file := os.open(filename, .Write)->unwrap(); - defer os.close(&file); - - // Create an io.Writer over the file stream using io.writer_make. - // Also, free it later by defering io.writer_free. This also flushes - // the internal buffer of io.Writer to make sure everything is written - // to the file. - file_writer := io.writer_make(&file); - defer io.writer_free(&file_writer); - - // The simplest way of writing a string to the file. - io.write(&file_writer, "This is the first line of text.\n"); - - // io.write_format can be used to "printf" into a file. - // printf can be thought of as io.write_format(&stdio.stream, ...). - io.write_format(&file_writer, "This is a {} line of text.\n", "formatted"); - - for i in 0 .. 5 { - io.write_format(&file_writer, "Another line numbered {}.\n", i); - } -} - -#doc "Reads example text from a file." -read_data_from_file :: (filename: str) { - // This is another way of opening a file. Because of the semantics - // of `for` loops over Iterators, they can behave like `with` - // statements in Python or `using` statements in C#. - for file in os.with_file(filename, .Read) { - // Create a io.Reader over the file stream. - file_reader := io.reader_make(file); - defer io.reader_free(&file_reader); - - // Read a single line. - first_line := io.read_line(&file_reader); - printf("First line: {}\n", first_line); - - // Use io.lines to create an iterator over the remaining - // lines in the file. - printf("Remaining lines:\n"); - for line, index in io.lines(&file_reader) { - printf("{}: {}\n", index, line); - } - } -} - -#doc "Reads example text from a file." -read_whole_file :: (filename: str) { - // This is the simplest way to get the entire content of a file - // into a string ([] u8). Also, defer "deleting" the string, which - // will free the memory allocated for the string. - contents := os.get_contents(filename); - defer delete(&contents); - - printf("Whole contents:\n{}\n", contents); -} - -main :: () { - filename := "test.txt"; - - write_data_into_file(filename); - read_data_from_file(filename); - read_whole_file(filename); -} - diff --git a/www/examples/index.json b/www/examples/index.json index 39d78c3..e395ae3 100644 --- a/www/examples/index.json +++ b/www/examples/index.json @@ -1,19 +1 @@ -[ - { - "name": "Reading from standard input", - "code": "stdin.onyx", - "html": "stdin.html" - }, - { - "name": "Interact with files", - "code": "files.onyx", - "html": "files.html" - }, - { - "name": "Fibonacci printer", - "code": "fib.onyx", - "html": "fib.html" - } -] - - +{"by_tag":{"io":["files","stdin"],"reader":["files","stdin"],"os":["files"],"file":["files"],"loops":["fib"],"iterators":["fib"],"input":["stdin"],"conv":["stdin"]},"list":[{"code":"","title":"File Operations","name":"files","tags":["io","reader","os","file"],"author":"Brendan Hansen","description":"This example shows various ways of reading and writing to a file. The core idea behind files in Onyx is that they extend the io.Stream structure, so you can use the core.io package to interact with them."},{"code":"","title":"Fibonacci Sequence","name":"fib","tags":["loops","iterators"],"author":"Brendan Hansen","description":"This example shows three different ways to do the same thing: compute Fibonacci numbers."},{"code":"","title":"Standard Input","name":"stdin","tags":["input","io","reader","conv"],"author":"Brendan Hansen","description":"This example reads a single line of input from standard input, splits it in half on the first space using string.bisect, converts both parts to integers using conv.parse, then prints the results using printf for formatted printing."}]} \ No newline at end of file diff --git a/www/examples/stdin.html b/www/examples/stdin.html index e659177..e9ad9dc 100644 --- a/www/examples/stdin.html +++ b/www/examples/stdin.html @@ -1 +1,39 @@ -This example reads a single line of input from standard input, splits it in half on the first space using string.bisect, converts both parts to integers using conv.parse, then prints the results using printf for formatted printing. +

Standard Input

+

Brendan Hansen

+
This example reads a single line of input from standard input, splits it in half on the first space using string.bisect, converts both parts to integers using conv.parse, then prints the results using printf for formatted printing.
+
// Use the necessary core libraries
+use core.io
+use core.string
+use core.conv
+
+// Use the printf function that lives in the core package.
+// This cannot be `use core.printf`, because that will look
+// for a package called `printf` in `core`.
+use core {
+    printf
+}
+
+main :: () {
+    // Create a io.Reader over the stdio.stream to be able scan
+    // the input in parts. Also, defer freeing the reader until
+    // the end of `main`.
+    stdin_reader := io.reader_make(&stdio.stream);
+    defer io.reader_free(&stdin_reader);
+
+    // Read a single line of input.
+    line := io.read_line(&stdin_reader);
+
+    // Split the line on the first space.
+    a_str, b_str := string.bisect(line, " ");
+
+    // Parse and convert both parts to i32s, with a default value
+    // of 0 if it fails to parse as an i32.
+    a_value := conv.parse(i32, a_str)->value_or(0);
+    b_value := conv.parse(i32, b_str)->value_or(0);
+
+    // Compute our result.
+    result := a_value + b_value;
+
+    // Output our result using formatted printing.
+    printf("{} + {} = {}\n", a_value, b_value, result);
+}
diff --git a/www/examples/stdin.onyx b/www/examples/stdin.onyx deleted file mode 100644 index 1f0d877..0000000 --- a/www/examples/stdin.onyx +++ /dev/null @@ -1,36 +0,0 @@ -// Use the necessary core libraries -use core.io -use core.string -use core.conv - -// Use the printf function that lives in the core package. -// This cannot be `use core.printf`, because that will look -// for a package called `printf` in `core`. -use core { - printf -} - -main :: () { - // Create a io.Reader over the stdio.stream to be able scan - // the input in parts. Also, defer freeing the reader until - // the end of `main`. - stdin_reader := io.reader_make(&stdio.stream); - defer io.reader_free(&stdin_reader); - - // Read a single line of input. - line := io.read_line(&stdin_reader); - - // Split the line on the first space. - a_str, b_str := string.bisect(line, " "); - - // Parse and convert both parts to i32s, with a default value - // of 0 if it fails to parse as an i32. - a_value := conv.parse(i32, a_str)->value_or(0); - b_value := conv.parse(i32, b_str)->value_or(0); - - // Compute our result. - result := a_value + b_value; - - // Output our result using formatted printing. - printf("{} + {} = {}\n", a_value, b_value, result); -} diff --git a/www/packages/core_packages.json b/www/packages/core_packages.json index 45e878e..fe0c015 100644 --- a/www/packages/core_packages.json +++ b/www/packages/core_packages.json @@ -83,5 +83,10 @@ "name": "otmp", "url": "https://github.com/onyx-lang/pkg-otmp", "description": "A string templating language, similar to Jinja or Mustache." + }, + { + "name": "webgl2", + "url": "https://github.com/onyx-lang/pkg-webgl2", + "description": "Bindings to WebGL 2. Accessible when targetting JS runtime." } ] diff --git a/www/static/css/new_style.css b/www/static/css/new_style.css index 86801b9..bdc10ec 100644 --- a/www/static/css/new_style.css +++ b/www/static/css/new_style.css @@ -38,7 +38,7 @@ body { background: var(--background); color: var(--text); - font-family: 'Oxanium', sans-serif; + font-family: sans-serif; } a { @@ -554,3 +554,31 @@ canvas#animation { background-color: var(--primary); } +.example-container { + margin: 0 auto; + max-width: 1200px; + display: grid; + + grid-template-columns: 1fr 1fr; + gap: 16px; +} + +.example-container > div { + padding: 8px; +} + +.example-container > div > div { + padding: 8px; +} + +.example-container > div > div > a { + border-bottom: none; +} + +.example-container .example-tag { + padding: 2px; + background-color: var(--primary); + border-radius: 4px; +} + +.example > .author { display: none; } diff --git a/www/templates/pages/example.html b/www/templates/pages/example.html new file mode 100644 index 0000000..fb8757b --- /dev/null +++ b/www/templates/pages/example.html @@ -0,0 +1,34 @@ +{{ block "title" }} +Onyx Examples +{{ endblock }} + +{{ let navbar_page = "examples" }} + +{{ block "page_content" }} + +
+

Onyx Examples

+

Back to example list

+
+ +
+ {% ex.html %} +
+ +
+
+

Want to learn more?

+
+

+ Visit the docs! +

+

+ You can learn more details about Onyx by visiting the docs! + There is more examples, a reference manual for the language, and documentation for the standard library. +

+
+ +{{ endblock }} + +{{ extends "pages/normal_page" }} + diff --git a/www/templates/pages/examples.html b/www/templates/pages/examples.html index 55fba14..226897c 100644 --- a/www/templates/pages/examples.html +++ b/www/templates/pages/examples.html @@ -11,19 +11,26 @@ Onyx Examples

This page provides several simple examples of Onyx code, showing how to do common things with the standard library.

-{{ foreach ex in examples }} -
-
-

{% ex.name %}

+
+ {{ foreach ex in examples }} +
+
+ + + +

{% ex.title %}

+ +
+ {{ foreach tag in ex.tags }} + {% tag %} + {{ endforeach }} +
+ +
{% ex.description %}
+
- -
- {% ex.html %} -
- -
{% ex.code %}
+ {{ endforeach }}
-{{ endforeach }}
-- 2.25.1