From 241dc9c99bed4dddbc748aad54cee5bf7d77ab92 Mon Sep 17 00:00:00 2001 From: polwex Date: Sun, 15 Jun 2025 02:29:59 +0700 Subject: lfg --- bs5/server/rsc/Date.ml | 15 ++++ bs5/server/rsc/Markdown.ml | 202 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 bs5/server/rsc/Date.ml create mode 100644 bs5/server/rsc/Markdown.ml (limited to 'bs5/server/rsc') diff --git a/bs5/server/rsc/Date.ml b/bs5/server/rsc/Date.ml new file mode 100644 index 0000000..5abf9c3 --- /dev/null +++ b/bs5/server/rsc/Date.ml @@ -0,0 +1,15 @@ +let is_today date = + let now = Unix.localtime (Unix.time ()) in + let d = Unix.localtime date in + now.tm_year = d.tm_year && now.tm_mon = d.tm_mon && now.tm_mday = d.tm_mday + +let format_time date = + let t = Unix.localtime date in + let hour = t.tm_hour mod 12 in + let hour = if hour = 0 then 12 else hour in + let ampm = if t.tm_hour >= 12 then "pm" else "am" in + Printf.sprintf "%d:%02d %s" hour t.tm_min ampm + +let format_date date = + let t = Unix.localtime date in + Printf.sprintf "%d/%d/%02d" (t.tm_mon + 1) t.tm_mday (t.tm_year mod 100) diff --git a/bs5/server/rsc/Markdown.ml b/bs5/server/rsc/Markdown.ml new file mode 100644 index 0000000..e8c8942 --- /dev/null +++ b/bs5/server/rsc/Markdown.ml @@ -0,0 +1,202 @@ +module List = struct + include List + let rec take lst n = + match (lst, n) with + | ([], _) -> [] + | (_, 0) -> [] + | (x :: xs, n) -> x :: take xs (n - 1) +end + +let convert_headings text = + text + |> Str.global_replace (Str.regexp "^#### \\(.*\\)$") "

\\1

" + |> Str.global_replace (Str.regexp "^### \\(.*\\)$") "

\\1

" + |> Str.global_replace (Str.regexp "^## \\(.*\\)$") "

\\1

" + |> Str.global_replace (Str.regexp "^# \\(.*\\)$") "

\\1

" + +let convert_emphasis text = + text + |> Str.global_replace + (Str.regexp "\\*\\*\\([^*]*\\)\\*\\*") + "\\1" + |> Str.global_replace + (Str.regexp "__\\([^_]*\\)__") + "\\1" + |> Str.global_replace (Str.regexp "\\*\\([^*]*\\)\\*") "\\1" + |> Str.global_replace (Str.regexp "_\\([^_]*\\)_") "\\1" + +let convert_code text = + text + |> Str.global_replace + (Str.regexp "```\\([^`]*\\)```") + "
\\1
" + |> Str.global_replace (Str.regexp "`\\([^`]*\\)`") "\\1" + +let convert_links text = + text + |> Str.global_replace + (Str.regexp "\\[\\([^]]*\\)\\](\\([^)]*\\))") + "\\1" + +let convert_lists text = + let lines = String.split_on_char '\n' text in + + let process_line line = + match line with + | line when Str.string_match (Str.regexp "^-\\s*\\(.*\\)$") line 0 -> + "
  • " ^ Str.matched_group 1 line ^ "
  • " + | line when Str.string_match (Str.regexp "^\\+\\s*\\(.*\\)$") line 0 -> + "
  • " ^ Str.matched_group 1 line ^ "
  • " + | line when Str.string_match (Str.regexp "^\\*\\s*\\(.*\\)$") line 0 -> + "
  • " ^ Str.matched_group 1 line ^ "
  • " + | line + when Str.string_match (Str.regexp "^\\d+\\.\\s*\\(.*\\)$") line 0 -> + "
  • " ^ Str.matched_group 1 line ^ "
  • " + | _ -> line + in + + let wrap_consecutive_items lines = + let rec aux acc current_list lines = + match (current_list, lines) with + | ([], []) -> List.rev acc + | (hd :: tl, []) -> + List.rev [ + ""; + ] @ acc + | ([], line :: rest) -> + if Str.string_match (Str.regexp "^
  • ") line 0 then + aux acc [line] rest + else + aux (line :: acc) [] rest + | (items, line :: rest) -> + if Str.string_match (Str.regexp "^
  • ") line 0 then + aux acc (line :: current_list) rest + else + aux + (line :: ("") :: acc) + [] + rest + in + aux [] [] lines + in + + lines + |> List.map process_line + |> wrap_consecutive_items + |> String.concat "\n" + +let wrap_lists text = + text + |> Str.global_replace + (Str.regexp "
  • .*
  • \\(\n
  • .*
  • \\)*") + "" + +let convert_blockquotes text = + let lines = String.split_on_char '\n' text in + + let rec process_lines acc in_quote lines = + match lines with + | [] when in_quote -> List.rev ("" :: acc) + | [] -> List.rev acc + | line :: rest -> + let trimmed = String.trim line in + if Str.string_match (Str.regexp "^>\\s*\\(.*\\)$") trimmed 0 then + let content = Str.matched_group 1 trimmed in + if in_quote then + process_lines (content :: acc) true rest + else + process_lines (content :: "
    " :: acc) true rest + else if trimmed = "" then + if in_quote then + process_lines ("
    " :: acc) false rest + else + process_lines (line :: acc) false rest + else if in_quote then + process_lines (line :: acc) true rest + else + process_lines (line :: acc) false rest + in + + lines |> process_lines [] false |> String.concat "\n" + +let convert_paragraphs text = + let lines = String.split_on_char '\n' text in + + let is_block_element line = + Str.string_match + (Str.regexp "^<\\(h[1-6]\\|ul\\|ol\\|blockquote\\|pre\\)>") + line + 0 + in + + let wrap_paragraphs lines = + let rec aux acc current_p lines = + match lines with + | [] when current_p <> "" -> + List.rev (("

    " ^ current_p ^ "

    ") :: acc) + | [] -> List.rev acc + | line :: rest when is_block_element line -> + if current_p <> "" then + aux (line :: ("

    " ^ current_p ^ "

    ") :: acc) "" rest + else + aux (line :: acc) "" rest + | line :: rest when String.trim line = "" -> + if current_p <> "" then + aux (("

    " ^ current_p ^ "

    ") :: acc) "" rest + else + aux acc "" rest + | line :: rest -> + let sep = + if current_p = "" then + "" + else + " " + in + aux acc (current_p ^ sep ^ String.trim line) rest + in + aux [] "" lines + in + + lines |> wrap_paragraphs |> String.concat "\n" + +let to_html markdown = + markdown + |> convert_headings + |> convert_emphasis + |> convert_code + |> convert_links + |> convert_lists + |> wrap_lists + |> convert_blockquotes + |> convert_paragraphs + |> String.trim + +let extract_text markdown = + markdown + |> Str.global_replace (Str.regexp "\\[([^]]*)\\]\\([^)]*\\)") "\\1" + |> Str.global_replace (Str.regexp "\\*\\*\\([^*]*\\)\\*\\*") "\\1" + |> Str.global_replace (Str.regexp "\\*\\([^*]*\\)\\*") "\\1" + |> Str.global_replace (Str.regexp "__\\([^_]*\\)__") "\\1" + |> Str.global_replace (Str.regexp "_\\([^_]*\\)_") "\\1" + |> Str.global_replace (Str.regexp "~~\\([^~]*\\)~~") "\\1" + |> Str.global_replace (Str.regexp "`\\([^`]*\\)`") "\\1" + |> Str.global_replace (Str.regexp "```[^`]*```") "" + |> Str.global_replace (Str.regexp "^#+ .*$") "\n" + |> Str.global_replace (Str.regexp "^#* .*$") "\n" + |> Str.global_replace (Str.regexp "> \\|>") "" + |> Str.global_replace (Str.regexp "\\[\\|\\]\\|\\(\\|\\)") "" + |> Str.global_replace (Str.regexp "-\\|\\+\\|\\*\\s+") "" + |> Str.global_replace (Str.regexp "^\\d+\\.\\s+") "" + |> Str.global_replace (Str.regexp "\\\\") "" + |> String.trim + +let summarize text ~words:n = + let words = Str.split (Str.regexp "[ \n\r\t]+") text in + let truncated = List.take words n in + let dots = + if List.length words > n then + "..." + else + "" + in + String.concat " " truncated ^ dots \ No newline at end of file -- cgit v1.2.3