simple-learning

Simple learning web program
git clone git://git.laack.co/simple-learning.git
Log | Files | Refs | README | LICENSE

commit 084c599ff5f7e057c367b9fa6c0f615cd599d1af
parent 2bec5677a4b7c1fbbc1d1ec291cba39502e69985
Author: Andrew Laack <andrew@laack.co>
Date:   Fri, 28 Aug 2026 20:36:08 -0500

Refactor to use line_format enum to describe the format of a given line, removing complex boolean unstructured structure.

Diffstat:
Mlearning/bin/parser.ml | 86++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Mlearning/bin/render.ml | 2+-
Mlearning/static/styles.css | 11-----------
Mlearning/templates/course_page.jingoo | 22+++++++++++++---------
4 files changed, 77 insertions(+), 44 deletions(-)

diff --git a/learning/bin/parser.ml b/learning/bin/parser.ml @@ -1,21 +1,44 @@ + +(* TODO: These should be doing prefix matching...*) + +type line_format = + | Normal + | HeaderL1 + | HeaderL2 + | HeaderL3 + | Embedded + | Preformatted + | Hidden + | Quote + | Link + | ListItem + +let line_format_map format = + match format with + | Normal -> "Normal", 0 + | HeaderL1 -> "HeaderL1", 2 + | HeaderL2 -> "HeaderL2", 3 + | HeaderL3 -> "HeaderL3", 4 + | Embedded -> "Embedded", 3 + | Preformatted -> "Preformatted", 3 + | Hidden -> "Hidden", 3 + | Quote -> "Quote", 2 + | Link -> "Link", 3 + | ListItem -> "ListItem", 2 + +let line_format_str format = + fst (line_format_map format) + +let line_format_char_cut format = + snd (line_format_map format) + type page_line = { - header_level: int; content: string; - is_embedded: bool; - is_preformatted: bool; - is_hidden: bool; - is_quote: bool; - is_link: bool; (* if is_embedded == true => not is_link *) - is_list: bool; + line_type: line_format; } -let permute_line line embedded hidden link quote list = - if embedded then (String.sub line 4 (String.length(line) - 4)) else - if hidden || link then String.sub line 3 (String.length(line) - 3) else - if quote || list then String.sub line 2 (String.length(line) - 2) - else line - -(* TODO: These should be doing prefix matching...*) +let permute_line line line_type = + let cut = line_format_char_cut line_type in String.sub line cut (String.length(line) - cut) let is_hidden line preformatted = if not preformatted && String.length(line) > 2 && line.[0] = '?' && line.[1] = '?' && line.[2] = ' ' then true else false @@ -32,16 +55,33 @@ let is_embedded_link line preformatted = let is_link line preformatted = if not preformatted && not (is_embedded_link line preformatted) && String.length(line) > 2 && line.[0] = '=' && line.[1] = '>' && line.[2] = ' ' then true else false +let header_count line preformatted = + if not preformatted then Basic_functions.count_prefix '#' line else 0 + +let is_h1 line preformatted = header_count line preformatted = 1 (* TODO: Make this more consistent with the others *) +let is_h2 line preformatted = header_count line preformatted = 2 +let is_h3 line preformatted = header_count line preformatted = 3 + +let get_line_type line preformatted = + let funs = [ + (Hidden, is_hidden); + (ListItem, is_list); + (Quote, is_quote); + (Embedded, is_embedded_link); + (Link, is_link); + (HeaderL1, is_h1); + (HeaderL2, is_h2); + (HeaderL3, is_h3); + ] in + let lt = (List.find_opt (fun (_, f) -> f line preformatted) funs) in + match lt with + | Some v -> fst v + | None -> Normal + let parse_simple_line line preformatted = - let hidden = is_hidden line preformatted in - let hash_count = if not preformatted then Basic_functions.count_prefix '#' line else 0 in - let embedded_link = is_embedded_link line preformatted in - (* This re-computes is embedded, but maintains the 1 bit of state invariant in exchange. *) - let link = is_link line preformatted in - let quote = is_quote line preformatted in - let list = is_list line preformatted in - - {header_level = hash_count; content = (permute_line line embedded_link hidden link quote list); is_embedded = embedded_link; is_preformatted = preformatted; is_hidden = hidden; is_link = link; is_quote = quote; is_list = list} + let cl_type = get_line_type line preformatted in + + {line_type = cl_type; content = (permute_line line cl_type)} let is_format_line cl = diff --git a/learning/bin/render.ml b/learning/bin/render.ml @@ -29,7 +29,7 @@ let render_sidebar s = (Jg_template.from_file "./templates/sidebar.jingoo" ~models:[("courses", get_courses)]) ^ s let page_line_to_tobj (line : Parser.page_line) = - Jg_types.Tobj [("header_level", Jg_types.Tint line.header_level); ("content", Jg_types.Tstr line.content); ("is_embedded", Jg_types.Tbool line.is_embedded); ("is_preformatted", Jg_types.Tbool line.is_preformatted); ("is_hidden", Jg_types.Tbool line.is_hidden); ("is_quote", Jg_types.Tbool line.is_quote); ("is_link", Jg_types.Tbool line.is_link); ("is_list", Jg_types.Tbool line.is_list)] + Jg_types.Tobj [("content", Jg_types.Tstr line.content); ("line_type", Jg_types.Tstr (Parser.line_format_str line.line_type))] let render_course_home course_name = (Jg_template.from_file "./templates/course_home.jingoo" ~models:[("pages", (Jg_types.Tlist (get_course_home course_name)))]) diff --git a/learning/static/styles.css b/learning/static/styles.css @@ -20,17 +20,6 @@ h3 { color: #580000 ; } -h4 { - color: #600000 ; -} -h5 { - color: #680000 ; -} - -h6 { - color: #700000 ; -} - pre-formatted { background: #f4f4f4; border: 1px solid #ddd; diff --git a/learning/templates/course_page.jingoo b/learning/templates/course_page.jingoo @@ -1,25 +1,29 @@ <div class="main"> {% for line in lines %} - {% if line.is_preformatted %} + {% if line.line_type == "Preformatted"%} <pre><pre-formatted>{{line.content}}</pre-formatted></pre> - {% else if line.is_quote %} + {% else if line.line_type == "Quote"%} <blockquote>{{line.content}}</blockquote> - {% else if line.is_list %} + {% else if line.line_type == "ListItem"%} <li>{{line.content}}</li> - {% else if line.is_link %} + {% else if line.line_type == "Link"%} <a href="{{line.content}}">{{line.content}}</a> - {% else if line.is_hidden %} + {% else if line.line_type == "Hidden"%} <details> <summary>{{line.content}}</summary> </details> - {% else if line.header_level >= 1 %} - <h{{line.header_level}}>{{line.content}}</h{{line.header_level}}> - {% else if line.is_embedded %} + {% else if line.line_type == "HeaderL1"%} + <h1>{{line.content}}</h1> + {% else if line.line_type == "HeaderL2"%} + <h2>{{line.content}}</h2> + {% else if line.line_type == "HeaderL3"%} + <h3>{{line.content}}</h3> + {% else if line.line_type == "Embedded"%} <iframe style="width: 100%; height: 600px;overflow:auto"; src="{{line.content}}"> </iframe> - {% else if line.header_level == 0 %} + {% else if line.line_type == "Normal"%} <content-block>{{line.content}}</content-block> {% endif %} {% endfor %}