Add code fences
authorFrank Duncan <frank@consxy.com>
Thu, 6 Jan 2022 22:27:08 +0000 (16:27 -0600)
committerFrank Duncan <frank@consxy.com>
Thu, 6 Jan 2022 22:27:08 +0000 (16:27 -0600)
src/main/parse.lisp

index b64cb22a09bf54be4ab300056499a656ac452b3a..af3fca9a4e73795c0de31d17a13707024633f4a4 100644 (file)
@@ -32,10 +32,23 @@ DESCRIPTION:
    ((line (car lines))
     (parser (getf (cadr (find-if #1'(funcall (getf $1 :checker) line) (reverse *line-parsers*) :key #'cadr)) :parser)))
    (when (not parser) (error "Weird!  Couldn't find a match for ~A" line))
-   (multiple-value-bind (parsed-line squash-prev) (funcall (funcall parser line) prev)
-    (if squash-prev
-     (parse-lines (cdr lines) parsed-line)
-     (cons prev (parse-lines (cdr lines) parsed-line)))))))
+   (multiple-value-bind (parsed-line squash-prev suspension) (funcall (funcall parser line) prev)
+    (cond 
+     (squash-prev (parse-lines (cdr lines) parsed-line))
+     (suspension
+      (let*
+       ((regex-to-find (car suspension))
+        (function-to-call (cadr suspension))
+        (pos
+         (position-if
+          (lambda (line) (cl-ppcre:scan regex-to-find line))
+          (cdr lines))))
+       (append
+        (list
+         prev
+         (funcall function-to-call (subseq (cdr lines) 0 (or pos (length lines)))))
+        (parse-lines (nthcdr (1+ pos) (cdr lines))))))
+     (t (cons prev (parse-lines (cdr lines) parsed-line))))))))
 
 (defun parse-texts (line)
  (cond
@@ -77,10 +90,14 @@ DESCRIPTION:
                  #'parse-inline
                  (coerce (second (multiple-value-list (cl-ppcre:scan-to-strings ,regex str))) 'list)))))))))
 
-; each parser function needs to return a function that takes the previous line and returns either
+; each parser function needs to return a function that takes the previous line and returns
 ;
-; a single element being the new element, and optionally a second values option about whether
-; the previous line should be consumed
+; the values:
+;   the new element
+;   whether the previous line should be consumed (optional)
+;   an optional list with two items, which suspends parsing until regex is found
+;     - the regex to end the suspension
+;     - the function to call with the list of lines
 
 (defun prev-h2 ()
  (lambda (prev)
@@ -90,6 +107,12 @@ DESCRIPTION:
  (lambda (prev)
   (if (textp prev) (values (h1 prev) t) (hr))))
 
+(defun inline-h1 (text) (lambda (prev) (h1 text)))
+(defun inline-h2 (text) (lambda (prev) (h2 text)))
+(defun inline-h3 (text) (lambda (prev) (h3 text)))
+(defun inline-h4 (text) (lambda (prev) (h4 text)))
+(defun inline-h5 (text) (lambda (prev) (h5 text)))
+
 (defun list-item (text)
  (lambda (prev)
   (let
@@ -106,8 +129,29 @@ DESCRIPTION:
 (defun default (text)
  (lambda (prev) (declare (ignore prev)) text))
 
+(defun codefence (codetype)
+ (lambda (prev)
+  (declare (ignore prev))
+  (values
+   nil
+   nil
+   (list
+    "^```$"
+    (lambda (lines)
+     (pre
+      (code
+       (format nil "~{~A~%~}" lines))))))))
+
 (defline-parser "-+" prev-h2)
 (defline-parser "=+" prev-h1)
+
+; These need to be in reverse order so they match correctly
+(defline-parser "##### *(.*)" inline-h5)
+(defline-parser "#### *(.*)" inline-h4)
+(defline-parser "### *(.*)" inline-h3)
+(defline-parser "## *(.*)" inline-h2)
+(defline-parser "# *(.*)" inline-h1)
+(defline-parser "```(.*)" codefence)
 (defline-parser " *\\* *(.*)" list-item)
 (defline-parser " *" emptiness)
 (defline-parser "(.*)" default)