-
Notifications
You must be signed in to change notification settings - Fork 0
/
typst-ts-compile.el
145 lines (124 loc) · 5.66 KB
/
typst-ts-compile.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
;;; typst-ts-compile.el --- Compile Typst Files -*- lexical-binding: t; -*-
;; Copyright (C) 2023-2024 The typst-ts-mode Project Contributors
;; 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 (&optional arg)
"Compile current typst file.
When use a prefix argument, don't preview the document after compilation.
ARG: prefix argument."
(interactive "P")
(unless arg
(add-hook 'compilation-finish-functions
(typst-ts-mode-compile-and-preview--compilation-finish-function
(current-buffer))))
(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-let ((typst-file (buffer-file-name buffer)))
(let ((res (concat (file-name-base typst-file) ".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