branch: elpa/typst-ts-mode
commit 770916c8a58d5181b34722e05ce2bdc5453193df
Author: Meow King <mr.meowk...@anche.no>
Commit: Meow King <mr.meowk...@anche.no>

    refactor: extract compilation related functions into typst-ts-compile.el
---
 .gitignore                          |   1 +
 typst-ts-compile.el                 | 139 +++++++++++++++++++++++++++++
 typst-ts-embedding-lang-settings.el |   4 +
 typst-ts-mode.el                    | 172 ++++++++----------------------------
 typst-ts-utils.el                   |  10 ++-
 typst-ts-watch-mode.el              |  28 ++++--
 6 files changed, 209 insertions(+), 145 deletions(-)

diff --git a/.gitignore b/.gitignore
index 05c1625e98..2f7f1f10ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
 *.elc
 indentation-test.typ
+/makem.sh
 
 # Added by cargo
 
diff --git a/typst-ts-compile.el b/typst-ts-compile.el
new file mode 100644
index 0000000000..dbcac7be47
--- /dev/null
+++ b/typst-ts-compile.el
@@ -0,0 +1,139 @@
+;;; typst-ts-compile.el --- Compile Typst Files  -*- lexical-binding: t; -*-
+;; Copyright (C) 2024 Meow King <mr.meowk...@anche.no>
+
+;; This file is NOT part of Emacs.
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+(require 'compile)
+
+(defgroup typst-ts-compile nil
+  "Typst TS Compilation."
+  :prefix "typst-ts-compile"
+  :group 'typst-ts)
+
+(defcustom typst-ts-compile-executable-location "typst"
+  "The location or name(if in variable `exec-path') for Typst executable."
+  :type 'string
+  :group 'typst-ts-compile)
+
+(defcustom typst-ts-compile-options ""
+  "User defined compile options for `typst-ts-compile'.
+The compile options will be passed to the end of
+`<typst-executable> compile <current-file>' command."
+  :type 'string
+  :group 'typst-ts)
+
+(defcustom typst-ts-compile-before-compilation-hook nil
+  "Hook runs after compile."
+  :type 'hook
+  :group 'typst-ts)
+
+(defcustom typst-ts-compile-after-compilation-hook nil
+  "Hook runs after compile.
+Note the requirement of this hook is the same as 
`compilation-finish-functions'.
+Also note that this hook runs with typst buffer(the buffer you are editing) as
+the current buffer."
+  :type 'hook
+  :group 'typst-ts)
+
+(defun typst-ts-compile--compilation-finish-function (cur-buffer)
+  "Compilation finish function.
+For `typst-ts-compile-after-compilation-hook' and
+`compilation-finish-functions'.  CUR-BUFFER: original typst buffer, in case
+user set `display-buffer-alist' option for compilation buffer to switch to
+compilation buffer before compilation."
+  (lambda (compilation-buffer msg)
+    (unwind-protect
+        (with-current-buffer cur-buffer
+          (run-hook-with-args 'typst-ts-compile-after-compilation-hook 
compilation-buffer msg))
+      (remove-hook 'compilation-finish-functions
+                   (typst-ts-compile--compilation-finish-function 
cur-buffer)))))
+
+(defun typst-ts-compile ()
+  "Compile current typst file."
+  (interactive)
+  (run-hooks typst-ts-compile-before-compilation-hook)
+
+  ;; The reason to take such a awkward solution is that 
`compilation-finish-functions'
+  ;; should be a global variable and also its functions. It doesn't work if we
+  ;; define them inside a let binding.
+  (add-hook 'compilation-finish-functions
+            (typst-ts-compile--compilation-finish-function (current-buffer)))
+  (compile
+   (format "%s compile %s %s"
+           typst-ts-compile-executable-location
+           (file-name-nondirectory buffer-file-name)
+           typst-ts-compile-options)
+   'typst-ts-compilation-mode))
+
+(defun typst-ts-compile-get-result-pdf-filename (&optional buffer check)
+  "Get the result PDF filename based on the name of BUFFER.
+If BUFFER is nil, it means use the current buffer.
+CHECK: non-nil mean check the file existence.
+Return nil if the BUFFER has not associated file or the there is
+no compiled pdf file when CHECK is non-nil."
+  (when buffer-file-name
+    (let ((res (concat (file-name-base (buffer-file-name buffer)) ".pdf")))
+      (if check
+          (when (file-exists-p res)
+            res)
+        res))))
+
+
+(defun typst-ts-mode-compile-and-preview--compilation-finish-function 
(cur-buffer)
+  "For `typst-ts-compile-and-preview' and `compilation-finish-functions'.
+CUR-BUFFER: original typst buffer, in case user set
+`display-buffer-alist' option for compilation buffer to switch to compilation
+buffer before compilation."
+  (lambda (_b _msg)
+    (unwind-protect
+        (browse-url (typst-ts-compile-get-result-pdf-filename cur-buffer))
+      (remove-hook 'compilation-finish-functions
+                   
(typst-ts-mode-compile-and-preview--compilation-finish-function cur-buffer)))))
+
+;;;###autoload
+(defun typst-ts-compile-and-preview ()
+  "Compile & Preview.
+Assuming the compile output file name is in default style."
+  (interactive)
+  ;; use a local variable version of `compilation-finish-functions' to shadow
+  ;; global version doesn't work
+  (add-hook 'compilation-finish-functions
+            (typst-ts-mode-compile-and-preview--compilation-finish-function
+             (current-buffer)))
+  (typst-ts-compile))
+
+(defvar typst-ts-compilation-mode-error
+  (cons (rx bol "error:" (+ not-newline) "\n" (+ blank) "┌─ "
+            (group (+ not-newline)) ":" ;; file
+            (group (+ num)) ":"         ;; start-line
+            (group (+ num)) "\n")       ;; start-col
+        '(1 2 3))
+  "Regexp for Error in compilation buffer.")
+
+;;;###autoload
+(define-compilation-mode typst-ts-compilation-mode "Typst Compilation"
+  "Customized major mode for typst watch compilation."
+  (setq-local compilation-error-regexp-alist-alist nil)
+  (add-to-list 'compilation-error-regexp-alist-alist
+               (cons 'typst-error typst-ts-compilation-mode-error))
+  (setq-local compilation-error-regexp-alist nil)
+  (add-to-list 'compilation-error-regexp-alist 'typst-error))
+
+(provide 'typst-ts-compile)
+
+;;; typst-ts-compile.el ends here
diff --git a/typst-ts-embedding-lang-settings.el 
b/typst-ts-embedding-lang-settings.el
index dcba2183e6..7372350db5 100644
--- a/typst-ts-embedding-lang-settings.el
+++ b/typst-ts-embedding-lang-settings.el
@@ -835,6 +835,8 @@ Use this function as one notifier of 
`treesit-parser-notifiers'."
 ;;; synchronizely) 
=============================================================
 
 (defun typst-ts-els--get-lang-input (lang)
+  "Get lowercase symbol of LANG.
+LANG should be either a symbol or string."
   (if (symbolp lang)
       (intern (downcase (symbol-name lang)))
     (if (stringp lang)
@@ -842,6 +844,8 @@ Use this function as one notifier of 
`treesit-parser-notifiers'."
       (error "LANG should be either symbol or string"))))
 
 (defun typst-ts-els--get-tags-input (tags)
+  "Get lowercase string(s) of TAGS.
+TAGS should be either a string or a list of strings."
   (if (stringp tags)
       (list (downcase tags))
     (if (and (listp tags)
diff --git a/typst-ts-mode.el b/typst-ts-mode.el
index feae32afc2..a91271e6c2 100644
--- a/typst-ts-mode.el
+++ b/typst-ts-mode.el
@@ -30,12 +30,12 @@
 ;;; Code:
 
 (require 'treesit)
-(require 'compile)
 (require 'outline)
 
 (require 'typst-ts-embedding-lang-settings)
 (require 'typst-ts-utils)
 (require 'typst-ts-faces)
+(require 'typst-ts-compile)
 (require 'typst-ts-watch-mode)
 
 (defgroup typst-ts nil
@@ -85,31 +85,6 @@ Note: this may take some time for documents with lot of raw 
blocks."
   :type 'boolean
   :group 'typst-ts)
 
-(defcustom typst-ts-mode-executable-location "typst"
-  "The location or name(if in variable `exec-path') for Typst executable."
-  :type 'string
-  :group 'typst-ts)
-
-(defcustom typst-ts-mode-compile-options ""
-  "User defined compile options for `typst-ts-mode-compile'.
-The compile options will be passed to the end of
-`<typst-executable> compile <current-file>' command."
-  :type 'string
-  :group 'typst-ts)
-
-(defcustom typst-ts-mode-before-compile-hook nil
-  "Hook runs after compile."
-  :type 'hook
-  :group 'typst-ts)
-
-(defcustom typst-ts-mode-after-compile-hook nil
-  "Hook runs after compile.
-Note the requirement of this hook is the same as 
`compilation-finish-functions'.
-Also note that this hook runs with typst buffer(the buffer you are editing) as
-the current buffer."
-  :type 'hook
-  :group 'typst-ts)
-
 ;; 
==============================================================================
 ;; TODO typst has three modes (namely 'markup', 'code' and 'math')
 ;; Currently only add common settings to syntax table
@@ -126,7 +101,7 @@ the current buffer."
   "You can customize this variable to override the whole default font lock 
rules.
 Like this:
 
-(setq typst-ts-mode-font-lock-rules
+ (setq typst-ts-mode-font-lock-rules
         (append
          (typst-ts-mode-font-lock-rules)
          \='(
@@ -175,7 +150,7 @@ BTW, if you want to enable/disable specific font lock 
feature, please change
   "See variable `typst-ts-mode-font-lock-rules'.")
 
 (defun typst-ts-mode-highlight-raw-block-fn (node _override _start _end)
-  "A function used in `typst-ts-mode-font-lock-rules'.
+  "A function used in function `typst-ts-mode-font-lock-rules'.
 This function assign `typst-ts-markup-rawblock-blob-face' to those raw block
 whose language cannot be found or be loaded.
 NODE."
@@ -666,18 +641,6 @@ NODE, PARENT and BOL see `treesit-indent-function'."
   "Generate name of NODE for displaying in Imenu."
   (treesit-node-text node))
 
-(defun typst-ts-mode-compile--compilation-finish-function (cur-buffer)
-  "For `typst-ts-mode-after-compile-hook' and `compilation-finish-functions'.
-CUR-BUFFER: original typst buffer, in case user set
-`display-buffer-alist' option for compilation buffer to switch to compilation
-buffer before compilation."
-  (lambda (compilation-buffer msg)
-    (unwind-protect
-        (with-current-buffer cur-buffer
-          (run-hook-with-args 'typst-ts-mode-after-compile-hook 
compilation-buffer msg))
-      (remove-hook 'compilation-finish-functions
-                   (typst-ts-mode-compile--compilation-finish-function 
cur-buffer)))))
-
 ;; outline-minor-mode 
================================================================================
 
 (defconst typst-ts-mode-outline-regexp "^[[:space:]]*\\(=+\\) "
@@ -736,46 +699,27 @@ Return the heading node when yes otherwise nil."
 When there is no relevant action to do it will execute the relevant function in
 the `GLOBAL-MAP' (example: `right-word')."
   (let ((heading (typst-ts-mode-heading--at-point-p))
-       ;; car function, cdr string of function for `substitute-command-keys'
-       (call-me/string
-        (pcase direction
-          ('left
-           (cons #'outline-promote
-                 "\\[typst-ts-mode-heading-decrease]"))
-          ('right
-           (cons #'outline-demote
-                 "\\[typst-ts-mode-heading-decrease]"))
-          ('up
-           (cons #'outline-move-subtree-up
-                 "\\[typst-ts-mode-heading-up]"))
-          ('down
-           (cons #'outline-move-subtree-down
-                 "\\[typst-ts-mode-heading-down]"))
-          (_ (error "%s is not one of: `right' `left'" direction)))))
+             ;; car function, cdr string of function for 
`substitute-command-keys'
+             (call-me/string
+              (pcase direction
+                ('left
+                 (cons #'outline-promote
+                             "\\[typst-ts-mode-heading-decrease]"))
+                ('right
+                 (cons #'outline-demote
+                             "\\[typst-ts-mode-heading-decrease]"))
+                ('up
+                 (cons #'outline-move-subtree-up
+                             "\\[typst-ts-mode-heading-up]"))
+                ('down
+                 (cons #'outline-move-subtree-down
+                             "\\[typst-ts-mode-heading-down]"))
+                (_ (error "%s is not one of: `right' `left'" direction)))))
     (if heading
-       (call-interactively (car call-me/string))
+             (call-interactively (car call-me/string))
       (call-interactively
        (keymap-lookup global-map (substitute-command-keys (cdr 
call-me/string)))))))
 
-(defun typst-ts-mode-compile ()
-  "Compile current typst file."
-  (interactive)
-  (run-hooks typst-ts-mode-before-compile-hook)
-
-  ;; The reason to take such a awkward solution is that 
`compilation-finish-functions'
-  ;; should be a global variable and also its functions. It doesn't work if we
-  ;; define them inside a let binding.
-  (add-hook 'compilation-finish-functions
-            (typst-ts-mode-compile--compilation-finish-function 
(current-buffer)))
-  (compile
-   (format "%s compile %s %s"
-           typst-ts-mode-executable-location
-           (file-name-nondirectory buffer-file-name)
-           typst-ts-mode-compile-options)
-   'typst-ts-compilation-mode))
-
-;; RETURN 
================================================================================
-
 (defun typst-ts-mode--item-on-line-p ()
   "Does the current line have an item node?
 Return the node when yes otherwise
@@ -895,58 +839,10 @@ When there is no section it will insert a heading below 
point."
     (insert heading-level " ")
     (indent-according-to-mode)))
 
-;;;###autoload
-(defun typst-ts-mode-preview (file)
-  "Open the result compile file.
-FILE: file path for the result compile file."
-  (interactive (list (concat (file-name-base buffer-file-name) ".pdf")))
-  ;; don't use `browse-url-of-file', which cannot open non-english documents
-  (browse-url file))
-
-(defun typst-ts-mode-compile-and-preview--compilation-finish-function 
(cur-buffer)
-  "For `typst-ts-mode-compile-and-preview' and `compilation-finish-functions'.
-CUR-BUFFER: original typst buffer, in case user set
-`display-buffer-alist' option for compilation buffer to switch to compilation
-buffer before compilation."
-  (lambda (_b _msg)
-    (unwind-protect
-        (with-current-buffer cur-buffer
-          (call-interactively #'typst-ts-mode-preview))
-      (remove-hook 'compilation-finish-functions
-                   
(typst-ts-mode-compile-and-preview--compilation-finish-function cur-buffer)))))
-
-;;;###autoload
-(defun typst-ts-mode-compile-and-preview ()
-  "Compile & Preview.
-Assuming the compile output file name is in default style."
-  (interactive)
-  ;; use a local variable version of `compilation-finish-functions' to shadow
-  ;; global version doesn't work
-  (add-hook 'compilation-finish-functions
-            (typst-ts-mode-compile-and-preview--compilation-finish-function
-             (current-buffer)))
-  (typst-ts-mode-compile))
-
-(defvar typst-ts-compilation-mode-error
-  (cons (rx bol "error:" (+ not-newline) "\n" (+ blank) "┌─ "
-            (group (+ not-newline)) ":" ;; file
-            (group (+ num)) ":"         ;; start-line
-            (group (+ num)) "\n")       ;; start-col
-        '(1 2 3))
-  "Regexp for Error in compilation buffer.")
-
-;;;###autoload
-(define-compilation-mode typst-ts-compilation-mode "Typst Compilation"
-  "Customized major mode for typst watch compilation."
-  (setq-local compilation-error-regexp-alist-alist nil)
-  (add-to-list 'compilation-error-regexp-alist-alist
-               (cons 'typst-error typst-ts-compilation-mode-error))
-  (setq-local compilation-error-regexp-alist nil)
-  (add-to-list 'compilation-error-regexp-alist 'typst-error))
-
-(defun typst-ts-mode-column-at-pos (pos)
+(defun typst-ts-mode-column-at-pos (point)
+  "Get the column at position POINT."
   (save-excursion
-    (goto-char pos)
+    (goto-char point)
     (current-column)))
 
 ;;;###autoload
@@ -1025,11 +921,19 @@ Assuming the compile output file name is in default 
style."
     (unless (eq execute-result 'success)
       (call-interactively (global-key-binding (kbd "TAB"))))))
 
+;;;###autoload
+(defun typst-ts-mode-preview (file)
+  "Open the result compile file.
+FILE: file path for the result compile file."
+  (interactive (typst-ts-compile-get-result-pdf-filename))
+  ;; don't use `browse-url-of-file', which cannot open non-english documents
+  (browse-url file))
+
 ;;;###autoload
 (defvar typst-ts-mode-map
   (let ((map (make-sparse-keymap)))
-    (define-key map (kbd "C-c C-c c") #'typst-ts-mode-compile-and-preview)
-    (define-key map (kbd "C-c C-c C") #'typst-ts-mode-compile)
+    (define-key map (kbd "C-c C-c c") #'typst-ts-compile-and-preview)
+    (define-key map (kbd "C-c C-c C") #'typst-ts-compile)
     (define-key map (kbd "C-c C-c w") #'typst-ts-watch-mode)
     (define-key map (kbd "C-c C-c p") #'typst-ts-mode-preview)
     (define-key map (kbd "M-<left>") #'typst-ts-mode-heading-decrease)
@@ -1197,10 +1101,12 @@ typst tree sitter grammar (at least %s)!" 
(current-time-string min-time))
 
   ;; Compile Command
   (ignore-errors
-    (format "%s compile %s %s"
-            typst-ts-mode-executable-location
-            (file-name-nondirectory buffer-file-name)
-            typst-ts-mode-compile-options))
+    (setq-local
+     compile-command
+     (format "%s compile %s %s"
+             typst-ts-compile-executable-location
+             (file-name-nondirectory buffer-file-name)
+             typst-ts-compile-options)))
 
   (when (>= emacs-major-version 30)
     (if (not typst-ts-mode-enable-raw-blocks-highlight)
diff --git a/typst-ts-utils.el b/typst-ts-utils.el
index aa6311ba1a..f94ce2c750 100644
--- a/typst-ts-utils.el
+++ b/typst-ts-utils.el
@@ -23,13 +23,15 @@
 
 (require 'treesit)
 
+(declare-function treesit-parser-list "treesit.c")
+
 (defun typst-ts-utils-parser-list (&optional buffer language)
   "An comptibility function for Emacs 29's `treesit-parser-list' function.
 BUFFER defaults to the current buffer.  If that buffer is an indirect
 buffer, its base buffer is used instead.  That is, indirect buffers
 use their base buffer's parsers.
 
-If LANGUAGE is non-nil, only return parsers for that language. "
+If LANGUAGE is non-nil, only return parsers for that language."
   (if (>= emacs-major-version 30)
       (funcall #'treesit-parser-list buffer language)
     (let ((parsers (treesit-parser-list buffer)))
@@ -43,7 +45,7 @@ If LANGUAGE is non-nil, only return parsers for that 
language. "
   "Return all the local parsers at POS.
 It's a copy of Emacs 30's `treesit-local-parsers-at' function.
 POS LANGUAGE WITH-HOST."
-  (if (>= emacs-major-version 30)
+  (if (fboundp 'treesit-local-parsers-at)
       (funcall #'treesit-local-parsers-at pos language with-host)
     (let ((res nil))
       (dolist (ov (overlays-at (or pos (point))))
@@ -60,7 +62,7 @@ POS LANGUAGE WITH-HOST."
   "Return all the local parsers between BEG END.
 It's a copy of Emacs 30's `treesit-local-parsers-on' function.
 BEG END LANGUAGE WITH-HOST."
-  (if (>= emacs-major-version 30)
+  (if (fboundp 'treesit-local-parsers-on)
       (funcall #'treesit-local-parsers-on beg end language with-host)
     (let ((res nil))
       (dolist (ov (overlays-in (or beg (point-min)) (or end (point-max))))
@@ -76,7 +78,7 @@ BEG END LANGUAGE WITH-HOST."
   "Get things from NODE by INSTRUCTIONS.
 It's a copy of Emacs 30's `treesit-node-get' function."
   (declare (indent 1))
-  (if (>= emacs-major-version 30)
+  (if (fboundp 'treesit-node-get)
       (treesit-node-get node instructions)
     (while (and node instructions)
       (pcase (pop instructions)
diff --git a/typst-ts-watch-mode.el b/typst-ts-watch-mode.el
index a6c4d9385e..3b0cb3b95f 100644
--- a/typst-ts-watch-mode.el
+++ b/typst-ts-watch-mode.el
@@ -15,12 +15,19 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-;;; Commentary: Minor mode for watching(hot compile) current typst file.
+;;; Commentary:
 
-;; 
+;; Minor mode for watching(hot compile) current typst file.
 
 ;;; Code:
 
+(require 'typst-ts-compile)
+
+(defgroup typst-ts-watch nil
+  "Typst TS Watch."
+  :prefix "typst-ts-watch"
+  :group 'typst-ts)
+
 (define-minor-mode typst-ts-watch-mode
   "Watch(hot compile) current typst file."
   :lighter " [Watch]"
@@ -33,27 +40,32 @@
   "User defined compile options for `typst-ts-watch'.
 The compile options will be passed to the
 `<typst-executable> watch <current-file>' sub-command."
-  :type 'string)
+  :type 'string
+  :group 'typst-ts-watch)
 
 (defcustom typst-ts-watch-process-name "*Typst-Watch*"
   "Process name for `typst watch' sub-command."
-  :type 'string)
+  :type 'string
+  :group 'typst-ts-watch)
 
 (defcustom typst-ts-watch-process-buffer-name "*Typst-Watch*"
   "Process buffer name for `typst watch' sub-command."
-  :type 'string)
+  :type 'string
+  :group 'typst-ts-watch)
 
 (defcustom typst-ts-display-watch-process-bufer-automatically t
   "Whether the typst watch process buffer should be displayed automatically.
 This means the buffer will be displayed when error occurs, hide when error
 is eliminated."
-  :type 'boolean)
+  :type 'boolean
+  :group 'typst-ts-watch)
 
 (defcustom typst-ts-display-watch-process-buffer-parameters
   `(display-buffer-at-bottom
     (window-height . fit-window-to-buffer))
   "Display buffer parameters."
-  :type 'symbol)
+  :type 'symbol
+  :group 'typst-ts-watch)
 
 (defvar typst-ts-before-watch-hook nil
   "Hook runs before compile.")
@@ -116,7 +128,7 @@ PROC: process; OUTPUT: new output from PROC."
    (start-process-shell-command
     typst-ts-watch-process-name typst-ts-watch-process-buffer-name
     (format "%s watch %s %s"
-            typst-ts-mode-executable-location
+            typst-ts-compile-executable-location
             (file-name-nondirectory buffer-file-name)
             typst-ts-watch-options))
    'typst-ts--watch-process-filter)

Reply via email to