240 lines
8.5 KiB
EmacsLisp
240 lines
8.5 KiB
EmacsLisp
;; mermaid mode
|
|
|
|
(defvar mermaid-mode-hook nil
|
|
"initial hook for mermaid mode"
|
|
)
|
|
|
|
(defun mermaid-compilation-mode-hook ()
|
|
"Hook function to set local value for `compilation-error-screen-columns'."
|
|
;; In Emacs > 20.7 compilation-error-screen-columns is buffer local.
|
|
(or (assq 'compilation-error-screen-columns (buffer-local-variables))
|
|
(make-local-variable 'compilation-error-screen-columns))
|
|
(setq compilation-error-screen-columns nil))
|
|
|
|
(defvar mermaid-output-format 'png
|
|
"The format of generated file")
|
|
|
|
(defvar mermaid-verbose nil
|
|
"Show verbose information when run compiler")
|
|
|
|
(defvar mermaid-compiler "mermaid"
|
|
"The compiler used to generate output")
|
|
|
|
(defvar mermaid-mode-map
|
|
(let ((map (make-sparse-keymap)))
|
|
;; add key bindings for mermaid mode here
|
|
;;
|
|
(define-key map "\C-j" 'newline-and-indent)
|
|
(define-key map "\C-c\C-c" 'mermaid-compile)
|
|
(define-key map "\C-c\C-v" 'mermaid-view)
|
|
map)
|
|
"Keymap for mermaid mode")
|
|
|
|
(defconst mermaid-font-lock-keywords-1
|
|
'(("^[ \t]*\\(graph\\|subgraph\\|end\\|loop\\|alt\\|gantt\\|title\\|section\\|dateFormat\\|sequenceDiagram\\|opt\\|participant\\|note\\|else\\|gitGraph\\|options\\)" . font-lock-keyword-face)
|
|
("^[ \t]*graph[ \t]+\\(TD|\\TB\\|BT\\RL\\|LR\\)" . font-lock-keyword-face)
|
|
("%%\\(.*$\\)" . font-lock-comment-face)
|
|
("{\\(.*\\)}" . font-lock-string-face)
|
|
(":\\([^%\012]*\\)[^%\012]*$" . font-lock-warning-face)
|
|
)
|
|
"keyword in mermaid mode"
|
|
)
|
|
|
|
(defconst mermaid-new-scope-regexp
|
|
"^[ \t]*\\(loop\\|opt\\|subgraph\\|graph\\|sequenceDiagram\\|gantt\\|gitGraph\\|{\\)\\([ \t]*\\|$\\)"
|
|
"keyword to start a new scope(indent level)")
|
|
|
|
(defconst mermaid-end-scope-regexp
|
|
"^[ \t]*\\(end\\|}\\)\\([ \t]*\\|$\\)"
|
|
"keyword for end a scope(maybe also start a new scope)")
|
|
|
|
(defconst mermaid-section-regexp
|
|
"^[ \t]*\\(section\\)[ \t]+"
|
|
"section keyword")
|
|
|
|
(defconst mermaid-else-regexp
|
|
"^[ \t]*\\(else\\)"
|
|
"else keyword")
|
|
|
|
(defconst mermaid-alt-regexp
|
|
"^[ \t]*\\(alt\\)"
|
|
"alt keyword")
|
|
|
|
(defun mermaid-output-ext ()
|
|
"get the extendsion of generated file"
|
|
(if (eq mermaid-output-format 'svg)
|
|
".svg"
|
|
".png"))
|
|
|
|
;;;###autoload
|
|
(defun mermaid-compile ()
|
|
(interactive)
|
|
(let ((cmd (concat mermaid-compiler
|
|
(if (eq mermaid-output-format 'svg)
|
|
" --svg "
|
|
" ")
|
|
(if mermaid-verbose
|
|
" --verbose "
|
|
" ")
|
|
(buffer-file-name)))
|
|
(buf-name "*mermaid compilation")
|
|
(compilation-mode-hook (cons 'mermaid-compilation-mode-hook compilation-mode-hook)))
|
|
(if (fboundp 'compilation-start)
|
|
(compilation-start cmd nil
|
|
#'(lambda (mode-name)
|
|
buf-name))
|
|
(compile-internal cmd "No more errors" buf-name))))
|
|
|
|
;;;###autoload
|
|
(defun mermaid-view ()
|
|
(interactive)
|
|
(let ((dst-file-name (concat (buffer-file-name)
|
|
(mermaid-output-ext))))
|
|
(if (file-exists-p dst-file-name)
|
|
(find-file-other-window dst-file-name)
|
|
(error "Please compile the it first!\n"))))
|
|
|
|
;; disable debug in default
|
|
;;
|
|
(defvar mermaid-debug-enabled nil
|
|
"enable/disable debug")
|
|
|
|
(defmacro mermaid-debug (fmt &rest args)
|
|
`(when mermaid-debug-enabled
|
|
(message ,fmt ,@args)))
|
|
|
|
(defun mermaid-indent-line ()
|
|
"indent current line in mermaid mode"
|
|
(interactive)
|
|
(mermaid-debug "line no @ %d\n" (line-number-at-pos))
|
|
(beginning-of-line)
|
|
(if (bobp)
|
|
(indent-line-to 0)
|
|
(let (cur-indent)
|
|
(cond
|
|
((looking-at mermaid-end-scope-regexp)
|
|
(progn
|
|
(mermaid-debug "found end scope\n")
|
|
(save-excursion
|
|
(forward-line -1)
|
|
(if (or (looking-at mermaid-new-scope-regexp)
|
|
(looking-at mermaid-alt-regexp))
|
|
(setq cur-indent (current-indentation))
|
|
(setq cur-indent (- (current-indentation) default-tab-width)))
|
|
(if (< cur-indent 0)
|
|
(setq cur-indent 0)))))
|
|
((looking-at mermaid-section-regexp)
|
|
(let ((found-section nil)
|
|
(need-search t))
|
|
(mermaid-debug "found section\n")
|
|
(save-excursion
|
|
(while need-search
|
|
(forward-line -1)
|
|
(cond
|
|
((looking-at mermaid-section-regexp)
|
|
(progn
|
|
(mermaid-debug "found section\n")
|
|
(setq found-section t)
|
|
(setq cur-indent (current-indentation))
|
|
(mermaid-debug "cur-indent %d\n" cur-indent)
|
|
(setq need-search nil)))
|
|
((or (looking-at mermaid-new-scope-regexp)
|
|
(looking-at mermaid-alt-regexp))
|
|
(progn
|
|
(mermaid-debug "found new scope\n")
|
|
(setq cur-indent (+ (current-indentation) default-tab-width))
|
|
(mermaid-debug "cur-indent %d\n" cur-indent)
|
|
(setq need-search nil)))
|
|
((looking-at mermaid-end-scope-regexp)
|
|
(progn
|
|
(mermaid-debug "found end scope\n")
|
|
(setq cur-indent (current-indentation))
|
|
(mermaid-debug "cur-indent %d\n" cur-indent)
|
|
(setq need-search nil)))
|
|
((bobp)
|
|
(progn
|
|
(setq cur-indent 0)
|
|
(setq need-search nil)))
|
|
(t t))))
|
|
(if (< cur-indent 0)
|
|
(setq cur-indent 0))))
|
|
((looking-at mermaid-else-regexp)
|
|
(let ((need-search t))
|
|
(mermaid-debug "else\n")
|
|
(save-excursion
|
|
(while need-search
|
|
(forward-line -1)
|
|
(cond
|
|
((or (looking-at mermaid-else-regexp)
|
|
(looking-at mermaid-alt-regexp))
|
|
(progn
|
|
(mermaid-debug "found matched alt/else\n")
|
|
(setq cur-indent (current-indentation))
|
|
(mermaid-debug "cur-indent %d\n" cur-indent)
|
|
(setq need-search nil)))
|
|
((looking-at mermaid-end-scope-regexp)
|
|
(progn
|
|
(mermaid-debug "found end\n")
|
|
(setq cur-indent (- (current-indentation) default-tab-width))
|
|
(setq need-search nil)))
|
|
((bobp)
|
|
(progn
|
|
(setq cur-indent 0)))
|
|
(t t))))))
|
|
(t
|
|
(let ((need-search t)
|
|
(start-scope (looking-at mermaid-new-scope-regexp)))
|
|
(mermaid-debug "normal indent\n")
|
|
(save-excursion
|
|
(while need-search
|
|
(forward-line -1)
|
|
(cond
|
|
((looking-at mermaid-end-scope-regexp)
|
|
(progn
|
|
(mermaid-debug "found end scope\n")
|
|
(setq cur-indent (current-indentation))
|
|
(mermaid-debug "cur-indent %d\n" cur-indent)
|
|
(setq need-search nil)))
|
|
((or (looking-at mermaid-new-scope-regexp)
|
|
(looking-at mermaid-alt-regexp))
|
|
(progn
|
|
(mermaid-debug "found begin scope\n")
|
|
(setq cur-indent (+ (current-indentation) default-tab-width))
|
|
(mermaid-debug "cur-indent %d\n" cur-indent)
|
|
(setq need-search nil)))
|
|
((looking-at mermaid-section-regexp)
|
|
(progn
|
|
(mermaid-debug "found section \n")
|
|
(if start-scope
|
|
(setq cur-indent (current-indentation))
|
|
(setq cur-indent (+ (current-indentation) default-tab-width)))
|
|
(mermaid-debug "cur-indent %d\n" cur-indent)
|
|
(setq need-search nil)))
|
|
((bobp)
|
|
(progn
|
|
(setq cur-indent 0)
|
|
(setq need-search nil)))))))))
|
|
(if cur-indent
|
|
(indent-line-to cur-indent)
|
|
(indent-line-to 0)))))
|
|
|
|
;;;###autoload
|
|
(defun mermaid-mode ()
|
|
"Major mode for editing mermaid scripts"
|
|
(interactive)
|
|
(kill-all-local-variables)
|
|
(use-local-map mermaid-mode-map)
|
|
(set (make-local-variable 'font-lock-defaults)
|
|
'(mermaid-font-lock-keywords-1))
|
|
(set (make-local-variable 'indent-line-function)
|
|
'mermaid-indent-line)
|
|
(set (make-local-variable 'comment-start) "%%")
|
|
(set (make-local-variable 'comment-end) "\n")
|
|
(setq font-lock-keywords-case-fold-search t)
|
|
(setq major-mode 'mermaid-mode)
|
|
(setq mode-name "mermaid")
|
|
(run-hooks 'mermaid-mode-hook)
|
|
)
|
|
|
|
(provide 'mermaid-mode)
|