~melchizedek6809/nujel.net

e4fe5b4e7ea92100aa80e78231c987a8ada7b3e4 — Benjamin Vincent Schulenburg 2 years ago 0bdadfb
MUCH better reference/documentation
A content/reference/core/generator.nuj => content/reference/core/generator.nuj +99 -0
@@ 0,0 1,99 @@
[import [pp-nujel] :pretty/nujel]

[defn closure-signature [f]
      [def args ""]
      [def arg-i 0]
      [def arguments [closure/arguments f]]
      [while arguments
        [if [pair? arguments]
            [when [car arguments] [set! args [fmt "{args} <span class=\"argument\" arg-i=\"{}\">{}</span>" [inc! arg-i] [car arguments]]]]
            [set! args [fmt "{args} <span class=\"argument rest-argument\" arg-i=\"{}\">{}</span>" [inc! arg-i] arguments]]]
        [cdr! arguments]]
      [fmt "<div class=\"signature\"><h1>{}</h1>{}</div>" [closure/name f] args]]

[defn closure-html-arg [f arg]
      [def i [index-of arg ":"]]
      [when [< i 0] [return arg]]
      [return [fmt "<div class=\"docstring-arg-name\">{}</div><div class=\"docstring-arg-desc\">{}</div>" [string/cut arg 0 i] [color-args f [string/cut arg [inc i]]]]]]

[defn closure-html-arguments [f args]
      [def i 0]
      [fmt "<div class=\"docstring-args-wrap\">{}</div>"
           [join [map [split args "\n"]
                      [fn [arg]
                          [fmt "<div class=\"docstring-arg\" arg-i=\"{}\">{}</div>" [inc! i] [closure-html-arg f arg]]]] ""]]]

[defn closure-html-return-val [f v]
      [fmt "<div class=\"docstring-return-val\">{}</div>" [color-args f v]]]

[defn color-args [f text]
      [def i 0]
      [def args [closure/arguments f]]
      [while args
             [inc! i]
             [if [pair? args]
                 [def arg [car args]]
                 [def arg args]]
             [set! text [join [split text [string arg]] [fmt "<span class=\"arg-ref\" arg-i=\"{}\">{arg}</span>" i]]]
             [cdr! args]]
      [return text]]

[defn closure-html-documentation [f]
      [def raw [closure/documentation f]]
      [when-not raw [return "<p>No documentation available</p>"]]
      [def parts [split raw "\n\n"]]
      [def ret [fmt "<h4>Summary</h4><p class=\"docstring-intro\">{}</p>" [color-args f [car parts]]]]
      [cdr! parts]
      [def len [length parts]]
      [when [> len 2]
        [set! ret [fmt "{ret}<h4>Description</h4>"]]]
      [while [> len 2]
        [set! ret [fmt "{ret}<p class=\"docstring-desc\">{}</p>" [color-args f [car parts]]]]
        [cdr! parts]
        [dec! len]]
      [when [>= len 2]
        [set! ret [fmt "{ret}<h4>Arguments</h4>{}" [closure-html-arguments f [car parts]]]]
        [cdr! parts]
        [dec! len]]
      [when [>= len 1]
        [set! ret [fmt "{ret}<h4>Return value</h4>{}" [closure-html-return-val f [car parts]]]]
        [cdr! parts]
        [dec! len]]
      [return ret]]

[defn closure-html-examples [f]
      [def examples [meta f :tests]]
      [when examples
        [cat "<h4>Examples</h4><pre class=\"docstring-examples source source-nujel\">"
             [-> examples
                 [map [fn [e] [pp-nujel [fmt "{:?}\n{:?}\n\n" [cadr e] [car e]] :html]]]
                 [join ""]]
             "</pre>"]]]

[defn closure-html-related [f]
      [def rel [meta f :related]]
      [when rel
        [cat "<h4>Related</h4><div class=\"docstring-related-wrap\">"
             [-> rel
                 [map [fn [e] [fmt "{} "  e]]]
                 [join ""]]
             "</div>"]]]

[defn generate-reference-for [f]
      [cat [closure-signature f]
           "<br/><br/>"
           [closure-html-documentation f]
           [closure-html-examples f]
           [closure-html-related f]]]

[defn generate-content-for [f]
      [def filename [fmt "{}.html" [closure/name f]]]
      [when [= filename ".html"] [return #nil]]
      [queue-content filename
                     @[:type :page :title [closure/name f] :category [closure/cat f]]
                     [fn [] [generate-reference-for f]]]]

[-> [symbol-table]
    [map resolve]
    [filter callable?]
    [for-each generate-content-for]]

M content/reference/index.html => content/reference/index.html +17 -4
@@ 5,8 5,21 @@ date: "2022-09-13"
+++

<h1>The Nujel reference</h1>
<p>This is an experiment in generating a usable reference using the builtin reflection abilities, they will be pretty terrible at first, but hopefully will improve over time in quality.</p>
<p>
    This is an experiment in generating a usable reference using the builtin reflection abilities,
    they will be pretty terrible at first, but hopefully will improve over time in quality.
</p>
<p>
    The ones that are categorized should hopefully have some passable documentation attached, the unsorted rest will hopefully shrink over time as I document the standard library.
</p>
<p>
    All the documentation here is generated by parsing the built-in documentation and some additional metadata. All the examples seen here are also just pretty printed unit tests which are run on every commit.
</p>

<nav>
    {{ [join [sort [map [navigation 2 "reference/"] [fn [v] [render-link v]]]] "<br/>"] }}
</nav>
\ No newline at end of file
{{
    [def cats @[]]
    [-> [symbol-table]
        [map resolve]
        [for-each [fn [a] [tree/set! cats [closure/cat a] #t]]]]
    [join [map [tree/keys cats] [fn [a] [component :CategoryNavigation @[:category a]]]] "<br/><br/>"]
}}

M main.nuj => main.nuj +9 -4
@@ 4,16 4,21 @@
;;; Most functionality is separated into modules that can be found under /ssg/

[import [rainbow] :ansi]
[import [get :as context/get] "ssg/context"]
[import [build :as content/build add-resources] "ssg/content"]
[import [get :as context-get] "ssg/context"]
[import [build-ctx build-queued generate-content build-frontmatter-index add-resources] "ssg/content"]
[import [load-builtin-themes load-components] "ssg/theme"]
[import [build-prev-next-list] "ssg/navigation"]

[defn main [args]
      :export
      [pfmtln "Welcome to the {} SSG" [rainbow "Nujel"]]
      [when [and [car args] [string? [car args]]] [cd [car args]]]
      [-> [context/get "./"]
      [-> [context-get "./"]
          load-builtin-themes
          load-components
          content/build
          build-frontmatter-index
          generate-content
          build-prev-next-list
          build-ctx
          build-queued
          add-resources]]

M ssg/content.nuj => ssg/content.nuj +45 -11
@@ 1,6 1,5 @@
[import [build :as loader/build] "loader"]
[import [parse-frontmatter frontmatter get-frontmatter] "theme"]
[import [build-prev-next-list] "navigation"]
[import [build :as loader/build mkdir-safe get-out-path] "loader"]
[import [render parse-frontmatter frontmatter get-frontmatter] "theme"]

[defn add-resources [ctx]
      :export


@@ 21,13 20,37 @@
[defn build-content [ctx path content-frontmatter build-fun]
      [when [file/file? [cat path "/config.nuj"]]
        [set! ctx [tree/merge ctx [file/eval [cat path "/config.nuj"]]]]]
      [doseq [c [directory/read-relative path] content-frontmatter]
      [doseq [c [directory/read-relative path] ctx]
             [if [file/dir? c]
                 [build-content ctx c content-frontmatter build-fun]
                 [build-fun ctx c content-frontmatter]]]]

[defn build [ctx]
      "Build everything"
[defn queue-content* [ctx base-path out-path fm content-fun]
      [def path [cat base-path out-path]]
      [def href [string/cut path [inc [length [tree/ref ctx :content-root-dir]]]]]
      [tree/set! fm :href href]
      [tree/set! fm :depth [- [length [split [tree/ref fm :href] "/"]] 1]]
      [tree/set! [tree/ref ctx :frontmatter] [string->keyword href] fm]
      [tree/set! [tree/ref ctx :generator-queue] [string->keyword href] @[:path path :meta fm :fun content-fun]]]


[defn generate-content [ctx]
      "Generate all autogenerated content"
      :export
      [build-content ctx
                     [tree/ref ctx :content-root-dir]
                     [tree/ref ctx :frontmatter]
                     [fn [ctx path content-frontmatter]
                         [when-not [== [path/basename path] "generator.nuj"]
                                   [return #nil]]
                       [def base-path [cat [path/dirname path] "/"]]
                       [defn queue-content [out-path fm content-fun]
                             [queue-content* ctx base-path out-path fm content-fun]]
                       [file/eval path [current-closure]]]]]


[defn build-frontmatter-index [ctx]
      "Load all the frontmatters and look generate datastructures necessary for building navigations"
      :export
      [def content-frontmatter @[]]
      [build-content ctx


@@ 37,10 60,21 @@
                         [load-frontmatter path
                                           [string/cut path [inc [length [tree/ref ctx :content-root-dir]]]]
                                           content-frontmatter]]]
      [tree/set! ctx :frontmatter content-frontmatter]
      [build-prev-next-list ctx]
      [tree/set! ctx :frontmatter content-frontmatter]]

[defn build-ctx [ctx]
      "Build everything"
      :export
      [build-content ctx
                     [tree/ref ctx :content-root-dir]
                     content-frontmatter
                     loader/build]
      [return ctx]]
                     [tree/ref ctx :frontmatter]
                     loader/build]]

[defn build-queued [ctx]
      "Build queued generator content"
      :export
      [doseq [d [tree/values [tree/ref ctx :generator-queue]] ctx]
             [def raw-content [[tree/ref d :fun]]]
             [def path [get-out-path ctx [tree/ref d :path]]]
             [mkdir-safe [path/dirname path]]
             [spit path [render ctx path [tree/ref d :meta] raw-content]]]]

M ssg/context.nuj => ssg/context.nuj +1 -1
@@ 12,4 12,4 @@
         :templates @[]

         :resources-needed @[]
         :loaders @[]]]
         :generator-queue @[]]]

M ssg/loader.nuj => ssg/loader.nuj +10 -3
@@ 1,10 1,12 @@
[import [render] "theme"]
[import [render split-frontmatter get-frontmatter] "theme"]

[defn get-out-path [ctx path]
      :export
      [cat [tree/ref ctx :deploy-dir]
           [string/cut path [length [tree/ref ctx :content-root-dir]]]]]

[defn mkdir-safe [full-path]
      :export
      [def parts [split full-path "/"]]
      [def path #nil]
      [while parts


@@ 15,10 17,15 @@
        [mkdir path]]]

[defn build-html [ctx path]
      "Loader that just copies the file over"
      "Loader that renders a HTML template"
      :export
      [def dest-path [get-out-path ctx path]]
      [mkdir-safe [path/dirname dest-path]]
      [spit dest-path [render ctx path]]
      [def page-parts [split-frontmatter [slurp path]]]
      [def meta [get-frontmatter path
                                 [string/cut path [inc [length [tree/ref ctx :content-root-dir]]]]
                                 [car page-parts]]]
      [spit dest-path [render ctx path meta [cdr page-parts]]]
      [return dest-path]]

[defn build-copy [ctx path]

M ssg/navigation.nuj => ssg/navigation.nuj +3 -1
@@ 22,7 22,7 @@
        [cdr! c]]
      [tree/set! ctx :prev-next-nav nav]]

[defn build [ctx depth prefix]
[defn build [ctx depth prefix category]
      "Build up a navigation and return a list of trees, describing the entries"
      :export
      [def l [-> [tree/values [tree/ref ctx :frontmatter]]


@@ 31,5 31,7 @@
        [set! l [filter l [fn [a] [== depth [tree/ref a :depth]]]]]]
      [when prefix
        [set! l [filter l [fn [a] [== prefix [cut [tree/ref a :href] 0 [buffer/length prefix]]]]]]]
      [when category
        [set! l [filter l [fn [a] [== category [tree/ref a :category]]]]]]
      [list/sort l [fn [a b] [< [tree/ref a :href]
                                [tree/ref b :href]]]]]

M ssg/theme.nuj => ssg/theme.nuj +15 -9
@@ 115,13 115,23 @@
[defn set-component-path! [new-path]
      [set! *cur-component-path* new-path]]

[defn urlescape [in]
      [with-string-port out
                        [dotimes [i [buffer/length in]]
                          [def c [buffer/ref in i]]
                          [case c
                                [#\# [out 'block-write "%23"]]
                                [#\& [out 'block-write "%26"]]
                                [#\? [out 'block-write "%3F"]]
                                [otherwise [out 'char-write c]]]]]]

[defn get-href* [ctx path target]
      [def name [string/cut path [inc [length [tree/ref ctx :content-root-dir]]]]]
      [def depth [- [length [split name "/"]] 1]]
      [def href [if [tree? target]
                    [tree/ref target :href]
                    target]]
      [dotimes [i depth href]
      [dotimes [i depth [urlescape href]]
        [set! href [cat "../" href]]]]

[defn render-link* [ctx path target]


@@ 140,8 150,8 @@
[defn get-href [target]
      [get-href* [get-ctx] [get-path] target]]

[defn navigation [depth prefix]
      [navigation/build [get-ctx] depth prefix]]
[defn navigation [depth prefix category]
      [navigation/build [get-ctx] depth prefix category]]

[defn get-posts []
      [def ret #nil]


@@ 208,14 218,10 @@
                 [set-component-path! old-component-path]
                 [return ret]]]]

[defn render [ctx path]
[defn render [ctx path meta raw-content]
      :export
      [def page-parts [split-frontmatter [slurp path]]]
      [def meta [get-frontmatter path
                                 [string/cut path [inc [length [tree/ref ctx :content-root-dir]]]]
                                 [car page-parts]]]
      [set-page-ctx! ctx path meta]
      [def content [parse-content ctx path [cdr page-parts] meta]]
      [def content [parse-content ctx path raw-content meta]]
      [def ret [template [tree/ref [get-meta] :type] meta content]]
      [reset-page-ctx!]
      [return ret]]

A ssg/theme/default/components/CategoryNavigation.html => ssg/theme/default/components/CategoryNavigation.html +4 -0
@@ 0,0 1,4 @@
<h2>{{ [def cur-cat [tree/ref props :category]] [keyword->string cur-cat] }}</h2>
<nav>
{{ [join [sort [map [navigation #nil #nil cur-cat] [fn [v] [render-link v]]]] "<br/>"] }}
</nav>
\ No newline at end of file

M ssg/theme/default/resources/main.css => ssg/theme/default/resources/main.css +94 -1
@@ 373,4 373,97 @@ h6 a{
.nujel-hl-12 {color:#528bff;}
.nujel-hl-13 {color:#7e0097;}
.nujel-hl-14 {color:#56b6c2;}
.nujel-hl-15 {color:#d7dae0; font-weight: bold;}
\ No newline at end of file
.nujel-hl-15 {color:#d7dae0; font-weight: bold;}

.signature {
	display: inline-block;
	font-size: 1.4rem;
}
.signature::before {
	content:"[";
	color:#d7dae0;
}
.signature::after {
	content:"]";
	color:#d7dae0;
}

.signature h1 {
	display: inline;
	padding: 0;
	margin: 0;
	font-size: inherit;
	font-weight: normal;
	font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
}

.signature > .argument {
	display:inline;
	padding:0;
	margin:0;
	font-size:1.4rem;
}
.signature > .argument.rest-argument::before {
	content:' . ';
	color:#d7dae0;
}

.signature > .argument[arg-i="1"] {color:#56b6c2;}
.signature > .argument[arg-i="2"] {color:#98c379;}
.signature > .argument[arg-i="3"] {color:#d5b06b;}
.signature > .argument[arg-i="4"] {color:#e06c75;}
.signature > .argument[arg-i="5"] {color:#c678dd;}
.signature > .argument[arg-i="6"] {color:#528bff;}

.docstring-intro {
	margin-bottom:2em;
}

.docstring-desc {
	margin-bottom: 1em;
}

.docstring-arg-name {
	display: block;
}
.docstring-arg-desc {
	display: inline-block;
	padding-left:1em;
}
.docstring-arg {
	margin-bottom: 1em;
}
.docstring-arg:last-child {
	margin-bottom: 0;
}

.docstring-return-val,
.docstring-args-wrap {
	margin-bottom: 2em;
}

.docstring-arg[arg-i="1"] .docstring-arg-name {color:#56b6c2;}
.docstring-arg[arg-i="2"] .docstring-arg-name {color:#98c379;}
.docstring-arg[arg-i="3"] .docstring-arg-name {color:#d5b06b;}
.docstring-arg[arg-i="4"] .docstring-arg-name {color:#e06c75;}
.docstring-arg[arg-i="5"] .docstring-arg-name {color:#c678dd;}
.docstring-arg[arg-i="6"] .docstring-arg-name {color:#528bff;}

.arg-ref[arg-i="1"] {color:#56b6c2;}
.arg-ref[arg-i="2"] {color:#98c379;}
.arg-ref[arg-i="3"] {color:#d5b06b;}
.arg-ref[arg-i="4"] {color:#e06c75;}
.arg-ref[arg-i="5"] {color:#c678dd;}
.arg-ref[arg-i="6"] {color:#528bff;}

p {
	margin: 0 0 1em 0;
	font-size: 1rem;
	line-height: 1.35em;
}

h4 {
	color: #8f949e;
	font-size: 1.4rem;
	margin-bottom: 0.25em;
}
\ No newline at end of file