diff --git a/db/meta.json b/db/meta.json index 2aae88d..664acff 100644 --- a/db/meta.json +++ b/db/meta.json @@ -1,7 +1,7 @@ { - "about-id": 2, - "base-url": "https://www.stranger.systems", + "title": "Stranger Systems", "placeholder-id": 0, + "base-url": "https://www.stranger.systems", "tagline": "Making software better by making it weird", - "title": "Stranger Systems" + "about-id": 2 } \ No newline at end of file diff --git a/db/posts/0.json b/db/posts/0.json index d978506..bf292ac 100644 --- a/db/posts/0.json +++ b/db/posts/0.json @@ -1,12 +1,12 @@ { - "edited-at": [ - ], - "hidden": true, - "placeholder": true, - "posted-at": "2025-02-05T04:54:41.218425-05:00", "slugs": [ ], "source": "/dev/null", + "edited-at": [ + ], "tags": [ - ] + ], + "posted-at": "2025-02-05T04:54:41.218425-05:00", + "hidden": true, + "placeholder": true } \ No newline at end of file diff --git a/db/posts/1.json b/db/posts/1.json index 62e539a..145b0c1 100644 --- a/db/posts/1.json +++ b/db/posts/1.json @@ -1,14 +1,12 @@ { - "edited-at": [ + "tags": [ ], - "hidden": false, - "markdown": true, - "posted-at": "2025-02-05T06:00:49.553777-05:00", "slugs": [ ], + "edited-at": [ + ], + "posted-at": "2025-02-05T06:00:49.553777-05:00", + "hidden": false, "source": "/home/nathan/Projects/Blog/projects/Markdown/MyNewBlog.md", - "tags": [ - "meta", - "raku" - ] + "markdown": true } \ No newline at end of file diff --git a/db/posts/2.json b/db/posts/2.json index fa46788..f356e0f 100644 --- a/db/posts/2.json +++ b/db/posts/2.json @@ -1,11 +1,11 @@ { + "posted-at": "2025-02-05T06:01:16.693698-05:00", + "markdown": true, "edited-at": [ ], - "hidden": true, - "markdown": true, - "posted-at": "2025-02-05T06:01:16.693698-05:00", "slugs": [ ], + "hidden": true, "source": "/home/nathan/Projects/Blog/projects/Markdown/About.md", "tags": [ ] diff --git a/db/posts/3.json b/db/posts/3.json index 527339e..ac66a8d 100644 --- a/db/posts/3.json +++ b/db/posts/3.json @@ -1,13 +1,13 @@ { - "edited-at": [ - ], "hidden": false, - "markdown": true, "posted-at": "2021-11-29T00:00:00Z", - "slugs": [ - ], - "source": "/home/nathan/Projects/Blog/projects/Markdown/CryptoSuite.md", "tags": [ "cryptography" - ] + ], + "source": "/home/nathan/Projects/Blog/projects/Markdown/CryptoSuite.md", + "edited-at": [ + ], + "slugs": [ + ], + "markdown": true } \ No newline at end of file diff --git a/db/posts/4.json b/db/posts/4.json deleted file mode 100644 index 9effd7d..0000000 --- a/db/posts/4.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "edited-at": [ - ], - "hidden": false, - "markdown": true, - "posted-at": "2025-02-07T06:45:08.536663-05:00", - "slugs": [ - ], - "source": "/home/nathan/Projects/Blog/projects/Markdown/2025/01-Jan/AdventOfBugs.md", - "tags": [ - "idris", - "advent-of-code" - ] -} \ No newline at end of file diff --git a/lib/Atom.rakumod b/lib/Atom.rakumod index 0efd238..0c0ad7b 100644 --- a/lib/Atom.rakumod +++ b/lib/Atom.rakumod @@ -41,12 +41,6 @@ sub post-to-item(BlogMeta:D $meta, Int:D $id, Post:D $post --> XML::Element) { XML::Element.new(:name, :attribs({:href($link), :rel})); $xml.append: XML::Element.new(:name, :nodes([$desc])) if $desc; - if $post.tags { - for $post.tags -> $tag { - $xml.append: - XML::Element.new(:name, :attribs({:term($tag)})); - } - } $xml } diff --git a/lib/Config.rakumod b/lib/Config.rakumod index 68c8172..5e043fc 100644 --- a/lib/Config.rakumod +++ b/lib/Config.rakumod @@ -1,24 +1,181 @@ use v6.e.PREVIEW; use HTML::Functional; - -use Render::Util; -use Render::Head; -use Render::Post; use DB::BlogMeta; use DB::Post; unit class Config; +method generate-head($title, BlogMeta:D $meta, $description?) { + head [ + meta :charset; + meta :name, :content; + meta :author :content; + do if $title ~~ Str:D { + title "$title — {$meta.title}"; + } else { + title $meta.title; + } + # Add description, if one exists + do if $description ~~ Str:D { + meta :description :content($description) + } else { + [] + } + # Preconnect to all our resource sources + link :rel :href; + link :rel :href; + link :rel :href :crossorigin; + link :rel :href; + # Load fonts, Iosevka for code, Open Sans for content, and boxicons for + # icons + link :rel, + :href; + link :rel, + :href; + link :rel, + :href; + # Link our style sheets + link :rel, + :href; + link :rel, + :href; + link :rel, + :href; + ]; +} + +method site-header(BlogMeta:D $meta) { + header :class, [ + div :class, [ + # TODO: Use a real image here + $meta.title + ]; + div :class, [ + $meta.tagline + ]; + div :class, [ + a :href, [ + icon 'home'; + ' '; + span [ + 'Home'; + ]; + ]; + a :href, [ + icon 'archive'; + ' '; + span [ + 'Archive'; + ]; + ]; + a :href, [ + icon 'info-circle'; + ' '; + span [ + 'About'; + ]; + ]; + a :href, [ + icon 'rss'; + ' '; + span [ + 'Feed'; + ]; + ]; + ]; + ] +} + +method post-date(Post:D $post) { + my $datetime = $post.posted-at; + my $timestamp = sprintf( + "%s %02d:%02d%s", + $datetime.yyyy-mm-dd, + ($datetime.hour % 12) || 12, + $datetime.minute, + $datetime.hour < 12 ?? 'am' !! 'pm' + ); + + div :class, :title("Posted At $timestamp"), [ + icon 'time'; + ' '; + $timestamp + ] +} + +method post-edit(Post:D $post) { + return [] unless $post.edited-at.elems; + my $datetime = $post.edited-at.max; + my $timestamp = sprintf( + "%s %02d:%02d%s", + $datetime.yyyy-mm-dd, + ($datetime.hour % 12) || 12, + $datetime.minute, + $datetime.hour < 12 ?? 'am' !! 'pm' + ); + + div :class, :title("Laste Edited At $timestamp"), [ + icon 'edit'; + ' '; + $timestamp + ] +} + +sub mins-to-string($mins) { + if $mins < 60 { + $mins.Str ~ "m" + } else { + my $h = $mins div 60; + my $m = $mins mod 60; + $h.Str ~ "h" ~ $m.Str ~ "m" + } +} + +method post-read-time(Post:D $post) { + my ($slow, $average, $fast) = $post.readtimes; + div :class, :title, [ + icon 'timer'; + ' '; + mins-to-string $slow; + ' '; + '/'; + ' '; + mins-to-string $average; + ' '; + '/'; + ' '; + mins-to-string $fast; + ] +} + +method post-info(Post:D $post) { + div :class, [ + self.post-date: $post; + self.post-edit: $post; + self.post-read-time: $post; + # TODO: Add tags once we have support for that + ]; +} + +method post-header(Post:D $post) { + header :class, [ + div :class, [ + h1 $post.title; + ]; + self.post-info: $post; + ] +} + # TODO: Support GFM admonitions method generate-post(Post:D $post, BlogMeta:D $meta) { my $content = $post.render-html; - my $head = generate-head($meta, $post.title, $post.description); + my $head = self.generate-head($post.title, $meta, $post.description); my $body = body [ - site-header $meta; + self.site-header: $meta; article :class, [ - post-header $post; + self.post-header: $post; div :class, [ $content; ] @@ -38,14 +195,20 @@ method generate-post(Post:D $post, BlogMeta:D $meta) { method generate-blurb(Int:D $id, $db) { my $post = $db.posts{$id}; my $desc = $post.description; - my $link = post-link $id, $post; + my @slugs = $post.all-slugs; + # Use the primary slug if there is one, the id if there isn't + my $link = do if @slugs.elems { + "/posts/by-slug/{@slugs[*-1]}.html" + } else { + "/posts/by-id/$id.html" + } div :class, [ div :class, [ a :href($link), span [ h2 $post.title; ]; ]; - post-info $post; + self.post-info: $post; if $desc ~~ Str:D { div :class, [ p $post.description; @@ -65,9 +228,9 @@ method generate-index($db) { self.generate-blurb: $pair.key, $db }); - my $head = generate-head($db.meta); + my $head = self.generate-head(Nil, $db.meta); my $body = body [ - site-header $db.meta; + self.site-header: $db.meta; div :class, [ h1 "Recent Posts" ], @most-recent; @@ -90,9 +253,9 @@ method generate-archive($db) { self.generate-blurb: $pair.key, $db }); - my $head = generate-head($db.meta); + my $head = self.generate-head(Nil, $db.meta); my $body = body [ - site-header $db.meta; + self.site-header: $db.meta; div :class, [ h1 "All Posts" ], @most-recent; @@ -107,76 +270,6 @@ method generate-archive($db) { "$html" } -method generate-tag-blurb($db, $tag, $limit?) { - sub post-to-link($id, $post) { - my $desc = $post.description; - my $link = post-link $id, $post; - div :class, [ - div :class, [ - a :href($link), span [ - h3 $post.title; - ]; - post-info $post; - if $desc ~~ Str:D { - div :class, [ - p $post.description; - ]; - } else { - [] - } - ]; - ] - } - my @posts = $db.sorted-posts.grep(-> $a { $tag (elem) $a.value.tags }); - if $limit { - @posts.=head($limit); - } - if @posts { - div :class, [ - span :class, [ - a :href("/tags/$tag.html"), [ - icon 'hash'; - $tag; - ]; - ]; - div :class, - @posts.map(-> $a {post-to-link $a.key, $a.value}); - ] - } else { - [] - } -} - -method generate-tags-page($db, @tags) { - my $head = generate-head($db.meta); - my $body = body [ - site-header $db.meta; - div :class, [ - h1 "Tags"; - ], @tags.map(-> $tag {self.generate-tag-blurb($db, $tag, 4)}); - ]; - - my $html = - html :lang, [ - $head, - $body - ]; - - "$html" -} - -method generate-tag-page($db, $tag) { - my $head = generate-head($db.meta); - my $body = body [ - site-header $db.meta; - self.generate-tag-blurb($db, $tag, 4); - ]; - - my $html = - html :lang, [ - $head, - $body - ]; - - "$html" +sub icon($icon) { + i(:class("bx bx-$icon")) } diff --git a/lib/DB.rakumod b/lib/DB.rakumod index dac655d..e56ec67 100644 --- a/lib/DB.rakumod +++ b/lib/DB.rakumod @@ -62,10 +62,10 @@ class PostDB { mkdir $posts-dir unless $posts-dir.e; # Write out metadata # TODO: Track changes and only write changed files - $dir.add('meta.json').spurt: $!meta.to-json(:sorted-keys); + $dir.add('meta.json').spurt: $!meta.to-json; # Write out posts (ids are the filename) for %!posts.kv -> $key, $value { - $posts-dir.add("$key.json").spurt: $value.to-json(:sorted-keys); + $posts-dir.add("$key.json").spurt: $value.to-json; } } @@ -105,15 +105,6 @@ class PostDB { my $about-path = $out-dir.add('about.html'); $about-path.unlink if $about-path.l; $by-id.add("{$!meta.about-id}.html").symlink: $about-path; - # Generate the tags pages - my @tags = %!posts.values.map(*.tags).flat.unique.sort; - $out-dir.add('tags.html').spurt: $config.generate-tags-page(self, @tags); - my $tags-dir = $out-dir.add('tags/'); - mkdir $tags-dir unless $tags-dir.e; - for @tags -> $tag { - $tags-dir.add("$tag.html").spurt: - $config.generate-tag-page(self, $tag); - } # Render the rss/atom feed my $atom-path = $out-dir.add('atom.xml'); my $atom = posts-to-atom self; diff --git a/lib/DB/MarkdownPost.rakumod b/lib/DB/MarkdownPost.rakumod index bbddc8e..0f189d5 100644 --- a/lib/DB/MarkdownPost.rakumod +++ b/lib/DB/MarkdownPost.rakumod @@ -1,12 +1,8 @@ use v6.e.PREVIEW; use Pandoc; -use Pygments; -use DB::Post; - - use JSON::Class:auth; -use File::Temp; +use DB::Post; #| A plain markdown post unit class MarkdownPost does Post is json(:pretty); @@ -24,17 +20,7 @@ method title(--> Str:D) { # Simply provide our source file to pandoc method render-html(--> Str:D) { - # Test to see if this posts contains any fenced code blocks, if so, - # pygmentize it through a temporary file - my $contents = $!source.slurp; - if $contents ~~ /'```'/ { - my $output = highlight-code $contents; - my ($filename, $filehandle) = tempfile; - $filehandle.spurt: $output, :close; - markdown-to-html $filename.IO - } else { - markdown-to-html $!source - } + markdown-to-html $!source } # Return our summary, if we have one, otherwise extract the first paragraph of diff --git a/lib/Pandoc.rakumod b/lib/Pandoc.rakumod index 6018021..713b376 100644 --- a/lib/Pandoc.rakumod +++ b/lib/Pandoc.rakumod @@ -6,7 +6,7 @@ use JSON::Fast; #| Run pandoc with the given arguments, dieing on failure sub pandoc(*@args --> Str:D) { # Call into pandoc - my $pandoc = run 'pandoc', '--no-highlight', @args, :out, :err; + my $pandoc = run 'pandoc', @args, :out, :err; # Collect the output my $output = $pandoc.out.slurp: :close; @@ -88,7 +88,6 @@ sub markdown-first-paragraph(IO::Path:D $file --> Str:D) is export { $para ~= "\n"; } when "Link" { - # TODO: Properly descend into links $para ~= $component[1][0]; } default { diff --git a/lib/Pygments.rakumod b/lib/Pygments.rakumod deleted file mode 100644 index 527012f..0000000 --- a/lib/Pygments.rakumod +++ /dev/null @@ -1,40 +0,0 @@ -#| Interaction with pygments -unit module Pygments; - -my token fence { '```' } -my token info-string { \w+ } -# TODO: Be more precise about this so we can handle backticks in code blocks -my token code { <-[`]>+ } -my token code-block { - <&fence> \h* \v - - <&fence> -} - -sub pygment(Str:D $code, Str:D $lang --> Str:D) { - my $pygments = run , $lang, :out, :in; - $pygments.in.spurt: $code, :close; - $pygments.out.slurp: :close; -} - -sub highlight-code(Str:D $input --> Str:D) is export { - my $text = $input; - # TODO: Figure out a way to exclude idris code so we can process both in the - # same file - while $text ~~ &code-block { - my $match = $/; - # Extract the match and have pygments colorize the code - my $code = $match.Str; - my $lang = $match.Str; - my $out = pygment $code, $lang; - ## Mangle the html to meet our needs - # Delete the existing div and construct a inside the
-       $out ~~ s:g/'<' \/? 'div' <-[>]>* '>'//;
-       $out ~~ s:g/'
'/
/;
-       $out ~~ s:g/'
'/<\/code><\/pre>/; - # Rename the classes to match our needs - $out ~~ s:g/'span class="' (\w+) '"'/span class="hl-{$/[0].lc}"/; - $text = $match.replace-with: $out; - } - $text -} diff --git a/lib/Render/Head.rakumod b/lib/Render/Head.rakumod deleted file mode 100644 index e7eb435..0000000 --- a/lib/Render/Head.rakumod +++ /dev/null @@ -1,68 +0,0 @@ -use v6.e.PREVIEW; -unit module Render::Head; - -use HTML::Functional; - -use Render::Util; -use DB::BlogMeta; - -sub generate-head(BlogMeta:D $meta, $title?, $description?) is export { - head [ - meta :charset; - meta :name, :content; - meta :author :content; - do if $title ~~ Str:D { - title "$title — {$meta.title}"; - } else { - title $meta.title; - } - # Add description, if one exists - optl $description ~~ Str:D, -> {meta :description :content($description)}; - # Preconnect to all our resource sources - link :rel :href; - link :rel :href; - link :rel :href :crossorigin; - link :rel :href; - # Load fonts, Iosevka for code, Open Sans for content, and boxicons for - # icons - link :rel, - :href; - link :rel, - :href; - link :rel, - :href; - # Link our style sheets - link :rel, - :href; - link :rel, - :href; - link :rel, - :href; - ] -} - -sub site-header(BlogMeta:D $meta) is export { - sub header-link($name, $path, $icon) { - a :href("$path"), [ - icon $icon; - ' '; - span $name; - ] - } - header :class, [ - div :class, [ - # TODO: Use a real image here - $meta.title - ]; - div :class, [ - $meta.tagline - ]; - div :class, [ - header-link 'Index', '/index.html', 'home'; - header-link 'Archive', '/archive.html', 'archive'; - header-link 'Tags', '/tags.html', 'purchase-tag-alt'; - header-link 'About', '/about.html', 'info-circle'; - header-link 'Feed', '/atom.xml', 'rss'; - ]; - ] -} diff --git a/lib/Render/Post.rakumod b/lib/Render/Post.rakumod deleted file mode 100644 index 826582e..0000000 --- a/lib/Render/Post.rakumod +++ /dev/null @@ -1,100 +0,0 @@ -use v6.e.PREVIEW; -unit module Render::Post; - -use Render::Util; -use DB::Post; - -use HTML::Functional; - -sub post-date(Post:D $post) is export { - my $datetime = $post.posted-at; - my $timestamp = sprintf( - "%s %02d:%02d%s", - $datetime.yyyy-mm-dd, - ($datetime.hour % 12) || 12, - $datetime.minute, - $datetime.hour < 12 ?? 'am' !! 'pm' - ); - - div :class, :title("Posted At $timestamp"), [ - icon 'time'; - ' '; - $timestamp - ] -} - -sub post-edit(Post:D $post) is export { - return [] unless $post.edited-at.elems; - my $datetime = $post.edited-at.max; - my $timestamp = sprintf( - "%s %02d:%02d%s", - $datetime.yyyy-mm-dd, - ($datetime.hour % 12) || 12, - $datetime.minute, - $datetime.hour < 12 ?? 'am' !! 'pm' - ); - - div :class, :title("Last Edited At $timestamp"), [ - icon 'edit'; - ' '; - $timestamp - ] -} - -sub post-read-time(Post:D $post) is export { - my ($slow, $average, $fast) = $post.readtimes; - div :class, :title, [ - icon 'timer'; - ' '; - mins-to-string $slow; - ' '; - '/'; - ' '; - mins-to-string $average; - ' '; - '/'; - ' '; - mins-to-string $fast; - ] -} - -sub post-tag(Str:D $tag) is export { - span :class, [ - a :href("/tags/$tag.html"), [ - icon 'hash'; - $tag; - ] - ] -} - -sub post-tags(Post:D $post) is export { - my @tags = $post.tags.sort; - if @tags { - @tags.=map(*.&post-tag); - div :class, [ - icon 'purchase-tag-alt'; - ' '; - intersperse(', ', @tags); - ] - } else { - [] - } -} - -sub post-info(Post:D $post) is export { - div :class, [ - post-date $post; - post-edit $post; - post-read-time $post; - post-tags $post; - ]; -} - -sub post-header(Post:D $post) is export { - header :class, [ - div :class, [ - h1 $post.title; - ]; - post-info $post; - ] -} diff --git a/lib/Render/Util.rakumod b/lib/Render/Util.rakumod deleted file mode 100644 index 05630a7..0000000 --- a/lib/Render/Util.rakumod +++ /dev/null @@ -1,54 +0,0 @@ -use v6.e.PREVIEW; -unit module Render::Util; - -use DB::Post; - -use HTML::Functional; - -sub opt($test, $item) is export { - if $test { - $item - } else { - [] - } -} - -sub optl($test, &item) is export { - if $test { - item - } else { - [] - } -} - -#| Link to the post by the primary slug, if there is one, linking to it by id -#| otherwise -sub post-link(Int:D $id, Post:D $post --> Str:D) is export { - my @slugs = $post.all-slugs; - if @slugs { - "/posts/by-slug/{@slugs[*-1]}.html" - } else { - "/posts/by-id/$id.html" - } -} - -sub icon($icon) is export { - i(:class("bx bx-$icon")) -} - -sub mins-to-string($mins) is export { - if $mins < 60 { - $mins.Str ~ "m" - } else { - my $h = $mins div 60; - my $m = $mins mod 60; - $h.Str ~ "h" ~ $m.Str ~ "m" - } -} - -sub intersperse (\element, +list) is export { - gather for list { - FIRST .take, next; - take slip element, $_; - } -} diff --git a/projects/Markdown/2025/01-Jan/AdventOfBugs.md b/projects/Markdown/2025/01-Jan/AdventOfBugs.md deleted file mode 100644 index 3242738..0000000 --- a/projects/Markdown/2025/01-Jan/AdventOfBugs.md +++ /dev/null @@ -1,98 +0,0 @@ -# Advent of bugs - -Near the start of january, after bumping into some ecosystem issues and lack of -a personal support library while working on the 2024 -[Advent of Code](https://adventofcode.com/) in Idris, I started working on a -project to solve all of the Advent of Code problems from all the years in a -single massive entirely literate Idris project and publish it as an mdbook. I'm -calling it -[Idris 2 by Extremely Contrived](https://static.stranger.systems/idris-by-contrived-example/) -example. - -## The Good - -This has been an amazingly fun project so far. AoC problems are nice and bite -sized, giving really good material to work with for incrementally introducing -more and more complex concepts. I have been following a sort of "weirdness -budget" for each day's solutions, letting myself build on the already -established weirdness from previous days. So far I'm 13 days in, and I've -already had excuses to introduce all sorts of fun concepts, effects, dependent -pattern matching, indexed type families, and refinement types, just to name a -few. - -Functional programming languages are a lot of fun to model puzzle problems in to -start with, but the new design space afforded by dependent typing offers a new, -wonderfully fun challenge of figuring out just what to show off while I'm -solving the puzzle. There have already been a few problems that I've wound up -spending a few days on just tweaking and refining until I was pleased with the -balance between weirdness expenditure and showing off what I want to show off in -a reasonably approachable way. - -A couple of personal favorites of mine so far have been the -[JSON parser](https://static.stranger.systems/idris-by-contrived-example/Parser/JSON.html), -and the -[`Digits` views](https://static.stranger.systems/idris-by-contrived-example/Util/Eff.html). -The JSON parser is written in a bespoke mini-library for doing effectively -parsing that I created just for this project, and refining the library to -optimize for readability of the parsers written in it was an absolute joy. The -digits views allowing pattern matching on normal integers as if they were lists -of digits was less fun to write[^1], they are amazingly fun to use. - -## The Bad - -I've had to write a lot of support code already. I can't really fault the -language, its a pretty new language in its pre-1.0 stage, in a pretty niche -area, dependent types are still quite scary to the majority of programmers, and -ecosystem improvement was a major goal of the project going in. I have already -had to write several "basic" data structures, and there's no sign the need to do -so will let up anytime soon[^6]. - -Honestly the most painful part has been the lack of support for Idris in -external tooling. Essentially every syntax highlighting library has _completely -ass_ support for Idris. I managed to eventually sneak proper semantic -highlighting into mdbook, it even plays nice with mdbook themes, but I had to -commit horrible, _horrible_ crimes to get this working[^2]. - -## The Ugly - -This isn't exactly a complaint, after all, ecosystem improvement was a goal -after all, but I've already run into 2 or 3 compiler bugs, a bug in the `pack` -package manager, and a weird behavior in katla that's a _maybe_ bug. - -I busted the part of the compiler that automatically inserts `force` and `delay` -calls to make interaction between lazy and strict code Just Work™: -[idris-lang/Idris2#3461](https://github.com/idris-lang/Idris2/issues/3461). I -had initially thought I had discovered just _one_ compiler bug, but it turns out -I also stumbled into an unrelated issue in the termination checker![^8] - -I broke the [pack](https://github.com/stefan-hoeck/idris2-pack) package manager -by, apparently, being the first person to try and upload a library to `pack-db` -with library code in literate files, in my -[Structures](https://git.sr.ht/~thatonelutenist/Structures) package, checking in -a new data structure motivated by my advent project, completely breaking the -automated docs generation: -[stefan-hoeck/idris2-pack!319](https://github.com/stefan-hoeck/idris2-pack/pull/319). -This one was especially wild to me, with how popular literate programs are in -the community, I would have never expected to be the first person to try this. - -## Looking Forward - -Despite the challenges, this has been a lovely experience so far. I greatly look -forward to pressing through to completion, whatever it may bring, and have a -trophy case full of bugs identified/fixed and new libraries to bring to the -ecosystem. - -[^1]: While perfectly understandable, it's not reasonable to expect the compiler - to be able to reason about primitive "machine" integers like this on its - own, needing to resort to so much `believe_me` on this one did make me a bit - sad - -[^6]: Well well well, if it isn't the consequences of my actions - -[^2]: Do not look at the `build-book` script if you value your sanity - -[^8]: Before anyone gets upset here, despite the name, the termination checker - doesn't actually solve the halting problem. It only automatically accepts a - subset of the language for which termination is a 'trivial' property, which - includes most code I've written in the language so far, but not nearly all - of it. diff --git a/projects/Markdown/RustPosting.md b/projects/Markdown/RustPosting.md deleted file mode 100644 index 632d2f1..0000000 --- a/projects/Markdown/RustPosting.md +++ /dev/null @@ -1,205 +0,0 @@ -# Rustposting - -Some example code with some potential problem characters: - -```rust -let newline_string = "hello \n world"; -let thing = *newline_string; -``` - -Here is some example rust code: - -```rust -fn main() { - // Statements here are executed when the compiled binary is called. - - // Print text to the console - println!("Hello World!"); -} -``` - -And a slightly less trivial example: - -```rust -fn main() { - // Variables can be type annotated. - let logical: bool = true; - - let a_float: f64 = 1.0; // Regular annotation - let an_integer = 5i32; // Suffix annotation - - // Or a default will be used. - let default_float = 3.0; // - let default_integer = 7; // - - // A type can also be inferred from context. - let mut inferred_type = 12; // Type i64 is inferred from another line. - inferred_type = 4294967296i64; - - // A mutable variable's value can be changed. - let mut mutable = 12; // Mutable - mutable = 21; - - // Error! The type of a variable can't be changed. - mutable = true; - - // Variables can be overwritten with shadowing. - let mutable = true; - - /* Compound types - Array and Tuple */ - - // Array signature consists of Type T and length as [T; length]. - let my_array: [i32; 5] = [1, 2, 3, 4, 5]; - - // Tuple is a collection of values of different types - // and is constructed using parentheses (). - let my_tuple = (5u32, 1u8, true, -5.04f32); -} -``` - -Toss in some type definitions to - -```rust -#[derive(Debug)] -struct Person { - name: String, - age: u8, -} - -// A unit struct -struct Unit; - -// A tuple struct -struct Pair(i32, f32); - -enum WebEvent { - // An variant may either be - PageLoad, - PageUnload, - // like tuple structs, - KeyPress(char), - Paste(String), - // or c-like structures. - Click { x: i64, y: i64 }, -} - -struct Point { - x: f64, - y: f64, -} - -// Implementation block, all associated functions & methods go in here -impl Point { - // This is an "associated function" because this function is associated with - // a particular type, that is, Point. - // - // Associated functions don't need to be called with an instance. - // These functions are generally used like constructors. - fn origin() -> Point { - Point { x: 0.0, y: 0.0 } - } - - // Another associated function, taking two arguments: - fn new(x: f64, y: f64) -> Point { - Point { x: x, y: y } - } -} - -``` - -Modules and imports - -```rust -#![allow(unused_variables)] - -use deeply::nested::function as other_function; -use std::fs::File; - -fn function() { - println!("called function()"); -} - -mod deeply { - pub mod nested { - pub fn function() { - println!("called deeply::nested::function()"); - } - } -} - -struct Val { - val: f64, -} - -struct GenVal { - gen_val: T, -} - -// impl of Val -impl Val { - fn value(&self) -> &f64 { - &self.val - } -} - -impl GenVal { - fn value(&self) -> &T { - &self.gen_val - } -} - -let a = Box::new(5i32); - -macro_rules! say_hello { - () => { - // The macro will expand into the contents of this block. - println!("Hello!") - }; -} - -macro_rules! calculate { - (eval $e:expr) => { - { - let val: usize = $e; // Force types to be unsigned integers - println!("{} = {}", stringify!{$e}, val); - } - }; -} - -fn give_adult(drink: Option<&str>) { - // Specify a course of action for each case. - match drink { - Some("lemonade") => println!("Yuck! Too sugary."), - Some(inner) => println!("{}? How nice.", inner), - None => println!("No drink? Oh well."), - } -} - -impl Person { - - // Gets the area code of the phone number of the person's job, if it exists. - fn work_phone_area_code(&self) -> Option { - // It would take a lot more code - try writing it yourself and see which - // is easier. - self.job?.phone_number?.area_code - } -} - -#[cfg(target_family = "unix")] -#[link(name = "m")] -extern { - // this is a foreign function - // that computes the square root of a single precision complex number - fn csqrtf(z: Complex) -> Complex; - - fn ccosf(z: Complex) -> Complex; -} - -fn main() { - let raw_p: *const u32 = &10; - - unsafe { - assert!(*raw_p == 10); - } -} -``` diff --git a/resources/code.css b/resources/code.css index 18edce7..b9d9c48 100644 --- a/resources/code.css +++ b/resources/code.css @@ -11,6 +11,7 @@ code { /* Styling for fenced code blocks */ pre > code { display: block; + white-space: pre-wrap; padding: 1rem; border-radius: 0.55rem / 0.5rem; word-wrap: normal; diff --git a/resources/colors.css b/resources/colors.css index 5974f21..54e6cc5 100644 --- a/resources/colors.css +++ b/resources/colors.css @@ -53,29 +53,23 @@ a:visited { .site-tagline { color: var(--dim-0); } -.post-body, .post-header, .post-blurbs, .tags, .tags .tag-blurb-post { +.post-body, .post-header, .post-blurbs { background-color: var(--bg-0); } -.post-blurb, .tags .tag-blurb { +.post-blurb { background-color: var(--bg-1); } -:not(.tags) .tag-blurb { - background-color: var(--bg-0); -} -:not(.tags) .tag-blurb-post { - background-color: var(--bg-1); -} -.post-title, .post-blurbs h1 { +.post-title, .post-blurbs > h1 { color: var(--green); } -.post-body h2, .post-body h3, .post-body h4 { +.post-body > h2, .post-body > h3, .post-body > h4 { color: var(--fg-1); } blockquote { background-color: var(--bg-1); } -/* Colorization for idris code blocks */ +/* Colorization for code blocks */ code { color: var(--code-fg-0); background-color: var(--code-bg-0); @@ -102,35 +96,3 @@ code { .hl-data { color: var(--code-red); } - -/* Colorization for pygments code blocks */ -.hl-kd, .hl-k, .hl-kc, .hl-bp { - color: var(--code-green); -} -.hl-n, .hl-nn { - color: var(--code-violet); -} -.hl-s, .hl-se { - color: var(--code-cyan); -} -.hl-nf, .hl-fm { - color: var(--code-blue); -} -.hl-c1, .hl-cm { - color: var(--code-dim-0); -} -.hl-mf, .hl-mi { - color: var(--code-magenta); -} -.hl-kt, .hl-nb, .hl-nc { - color: var(--code-orange); -} -.hl-cp { - color: var(--code-red); -} -.hl-se { - font-style: italic; -} -.hl-fm, .hl-k, .hl-o, .hl-kp { - font-weight: bold; -} diff --git a/resources/main.css b/resources/main.css index 4b54d5e..fad0412 100644 --- a/resources/main.css +++ b/resources/main.css @@ -2,7 +2,6 @@ font-family: "Open Sans", sans-serif, serif; /* Variables */ --content-width: 60rem; - --blurb-width: 45%; --header-width: 35rem; --box-padding-vert: 1rem; --box-padding-horz: 1rem; @@ -19,13 +18,6 @@ } } -/* slightly larger than blurb-width to account for padding/margins */ -@media screen and (max-width: 40rem) { - :root { - --blurb-width: 100%; - } -} - /* Main Body and Post Flexboxs */ body, .post { display: flex; @@ -33,9 +25,6 @@ body, .post { align-items: center; gap: var(--box-gap); } -.post { - width: 100%; -} /* Style the site header */ .site-header { @@ -86,11 +75,11 @@ body, .post { border-radius: var(--box-radius); box-sizing: border-box; } -.post-body p { +.post-body > p { margin: auto var(--box-margin-horz); align-self: stretch; } -.post-title h1 { +.post-title > h1 { margin-top: 0px; margin-bottom: 0px; } @@ -105,7 +94,7 @@ body, .post { .post-read-time { text-decoration: underline dotted; } -.post-body h2, .post-body h3, .post-body h4 { +.post-body > h2, .post-body > h3, .post-body > h4 { text-align: center; } .post-blurbs { @@ -135,56 +124,3 @@ blockquote { border-radius: var(--box-radius); padding: var(--box-padding-vert) var(--box-padding-horz); } - -/* Style the tags blurbs and page */ -.tags { - display: flex; - flex-direction: column; - align-items: center; - gap: var(--box-gap); - max-width: var(--content-width); - /* min-width: var(--blurb-width); */ - padding: var(--box-padding-vert) var(--box-padding-horz); - border-radius: var(--box-radius); - box-sizing: border-box; -} -.tag-blurb { - width: 100%; - display: flex; - flex-direction: column; - align-items: center; - gap: var(--box-gap); - border-radius: var(--box-radius); - box-sizing: border-box; -} -.tag-blurb-links { - display: block; - border-radius: var(--box-radius); - border-radius: var(--box-radius); - display: flex; - flex-flow: row wrap; - gap: var(--box-gap); - align-items: stretch; - box-sizing: border-box; - gap: var(--box-gap); - padding: var(--box-padding-vert) var(--box-padding-horz); -} -.tag-blurb-post { - font-size: 0.8rem; - width: var(--blurb-width); - display: flex; - flex-direction: column; - align-items: center; - gap: var(--box-gap); - box-sizing: border-box; - flex-shrink: 1; - flex-grow: 1; - border-radius: var(--box-radius); - padding: var(--box-padding-vert) var(--box-padding-horz); -} -.tag-blurb-title { - margin-top: var(--box-margin-vert); - margin-bottom: 0; - font-size: 1.5em; - font-weight: bold; -}