branch: elpa/typst-ts-mode
commit 770916c8a58d5181b34722e05ce2bdc5453193df
Author: Meow King <[email protected]>
Commit: Meow King <[email protected]>
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 <[email protected]>
+
+;; 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)