diff --git a/md4tj_parse.el b/md4tj_parse.el index 01b2803..461f928 100644 --- a/md4tj_parse.el +++ b/md4tj_parse.el @@ -3,6 +3,7 @@ ;;; Commentary: ;;; Code: + (require 'cl-lib) (defun getline () @@ -55,39 +56,97 @@ "`\\(.*\\)`" "\\1" line)))))) +(defun md4tj-clean-multiline (line) + "Clean LINE of markdown syntax for ul." + (replace-regexp-in-string + "^```" "" + (replace-regexp-in-string + "^[0-9]+\\. " "" + (replace-regexp-in-string "^- " "" line)))) + +(defun md4tj-clean-code-for-html (line) + "Escape characters in LINE that would be misinterpreted by the browser." + (string-replace + "<" "<" + (string-replace ">" ">" line))) + + ;; Note: a "block" is the smallest unit of parsing ;; It is normally a line of the code, but can be ;; multiple lines in the case of a block (NI) -(defun md4tj-process-block (codeblock) - "Process CODEBLOCK and return html." - (cond ((string-match "^#+ " codeblock) (md4tj-process-header (md4tj-process-line codeblock))) - ((string= "---" codeblock) "
") - ((= (length codeblock) 0) "
") - (t (md4tj-process-paragraph (md4tj-process-line codeblock))))) +(defun md4tj-process-block (codeblock state) + "Process CODEBLOCK with STATE and return html." + (let ((cleanline (md4tj-clean-multiline codeblock))) + (concat + ;; Beginning of multiline block + (cond ((eq state 'beginul) "\n") + ((eq state 'endol) "\n") + ((eq state 'endcode) "\n\n") + (t "")) + + ;; Body + (cond ((or (eq state 'code) (eq state 'begincode)) (md4tj-clean-code-for-html cleanline)) + ((string-match "^#+ " cleanline) (md4tj-process-header (md4tj-process-line cleanline))) + ((string= "---" cleanline) "
") ;; horizontal line + ((= (length cleanline) 0) "
") ;; blank line + (t (md4tj-process-paragraph (md4tj-process-line cleanline)))) + + ;; End of multiline block + (cond ((or (eq state 'ul) (eq state 'beginul)) "") + ((or (eq state 'ol) (eq state 'beginol)) "") + ((eq state 'code) "") + (t ""))))) -(defun md4tj-next-block () - "Retrieve the next block in the open file." - (let ((currline (getline))) - (cond ((string-match "^- " currline) nil) ;; TODO ul's - ((string-match "^[0-9]+\\. " currline) nil) ;; TODO ol's - (t currline)))) +(defun md4tj-next-state (currline prevstate) + "Return the state based on CURRLINE and PREVSTATE." + (cond ((and (string-match "^- " currline) (not (or (eq prevstate 'beginul) (eq prevstate 'ul))) 'beginul)) + ((and (string-match "^- " currline) (or (eq prevstate 'beginul) (eq prevstate 'ul)) 'ul)) + ((and (not (string-match "^- " currline)) (or (eq prevstate 'ul) (eq prevstate 'beginul))) 'endul) + ((and (string-match "^[0-9]+\\. " currline) (not (or (eq prevstate 'beginol) (eq prevstate 'ol))) 'beginol)) + ((and (string-match "^[0-9]+\\. " currline) (or (eq prevstate 'beginol) (eq prevstate 'ol)) 'ol)) + ((and (not (string-match "^[0-9]+\\. " currline)) (or (eq prevstate 'ol) (eq prevstate 'beginol))) 'endol) + ((and (string-match "^```" currline) (not (or (eq prevstate 'begincode) (eq prevstate 'code))) 'begincode)) + ((and (not (string-match "```$" currline)) (or (eq prevstate 'begincode) (eq prevstate 'code)) 'code)) + ((and (string-match "```$" currline) (or (eq prevstate 'code) (eq prevstate 'begincode))) 'endcode) + (t 'normal))) + +(defun md4tj-finalize (state) + "Finalizes HTML document by inserting missing end tags based on STATE." + (concat + (cond ((or (eq state 'beginul) (eq state 'ul)) "") + ((or (eq state 'beginol) (eq state 'ol)) "") + ((or (eq state 'begincode) (eq state 'code)) "") + (t "")) + "\n" + "")) (defun md4tj-parse (mdfile outfile) "Entry point to parse MDFILE and output to OUTFILE." (let ((inbuf (generate-new-buffer " in")) - (outbuf (generate-new-buffer " out"))) + (outbuf (generate-new-buffer " out")) + (state 'normal) + (line nil)) (set-buffer inbuf) (insert-file-contents mdfile) (goto-char (point-min)) (set-buffer outbuf) + (insert "\n") (while (with-current-buffer inbuf (< (point) (point-max))) + (setq line (with-current-buffer inbuf (getline))) + (setq state (md4tj-next-state line state)) + (print line) ;; Insert next line(s) into output file - (insert (concat (md4tj-process-block (with-current-buffer - inbuf - (md4tj-next-block))) - "\n")) + (insert (concat (md4tj-process-block line state) "\n")) ;; Advance input file by a line (with-current-buffer inbuf (forward-line))) + (insert (md4tj-finalize state)) + ;; Write outbuf to outfile (write-region nil nil outfile nil))) (provide 'md4tj_parse) diff --git a/test_file.html b/test_file.html index 6c47304..b7c2d9a 100644 --- a/test_file.html +++ b/test_file.html @@ -1,7 +1,32 @@ +

Hello world!

Hello world!

Hello world!

Hello world!


Example website

-

Example image

+

Example

+
+ +
+
    +
  1. ordered item 1

  2. +
  3. ordered item 2

  4. +
+
+
+
+#include <stdio.h>
+int main() {
+	printf("%s\n", "Hello World!");
+	return 0;
+}
+
+
+
+ + \ No newline at end of file diff --git a/test_file.md4tj b/test_file.md4tj index 730a5c3..69620d7 100644 --- a/test_file.md4tj +++ b/test_file.md4tj @@ -4,4 +4,19 @@ #### Hello ***world***! [Example website](https://example.com) -[Example image](image.jpg) \ No newline at end of file +![Example image](usbs.png) + +- unordered item 1 +- unordered item 2 +- unordered item 3 + +1. ordered item 1 +2. ordered item 2 + +``` +#include +int main() { + printf("%s\n", "Hello World!"); + return 0; +} +``` \ No newline at end of file