yatex

view yatexflt.el @ 531:6ea85aaae6f2

Workaround for Emacs26 (switch-to-buffer)
author HIROSE Yuuji <yuuji@gentei.org>
date Wed, 30 May 2018 08:33:07 +0900
parents cef987df070f
children ab6c176c676a
line source
1 ;;; yatexflt.el --- YaTeX filter command utilizer -*- coding: sjis -*-
2 ;;;
3 ;;; (c)1993-2018 by HIROSE Yuuji.[yuuji@yatex.org]
4 ;;; Last modified Sun Jan 21 16:33:16 2018 on firestorm
5 ;;; $Id$
7 ;;; Commentary:
8 ;;;
9 ;;; This lisp enables passing inline text to some external filter
10 ;;; command to generate files such as graphic files.
11 ;;;
12 ;;; Typical situation is using blockdiag/dot(graphviz) command to
13 ;;; generate png/pdf file.
14 ;;;
15 ;;; Example:
16 ;;;
17 ;;; [[LaTeX Source]]
18 ;;; %#BEGIN FILTER{foo.pdf}{dot -T %t -o o}
19 ;;; \if0
20 ;;; ===
21 ;;; digraph {
22 ;;; A -> B;
23 ;;; B -> C;
24 ;;; }
25 ;;; ===
26 ;;; \fi
27 ;;; %#END
28 ;;; \includegraphics{foo.pdf}
29 ;;;
30 ;;; In this case above, when you type `[prefix] t e' between two
31 ;;; `===' lines, the content in a region are fed to dot command as
32 ;;; follows:
33 ;;;
34 ;;; echo TEXT | dot -T pdf -o foo.pdf
35 ;;;
36 ;;; Then foo.pdf file will be generated and the image (as PNG) will
37 ;;; be displayed in the next window.
40 ;;; Code:
41 (require 'yatexlib)
42 (defvar YaTeX-filter-special-env-alist-default
43 '((".blockdiag"
44 "blockdiag -T %t -o %o -"
45 "blockdiag {
46 default_fontsize = 32;
47 A -> B;
48 }")
49 (".seqdiag" "seqdiag -T %t -o %o -"
50 "seqdiag {
51 client -> server [label = \"SYN\"];
52 client <- server [label = \"SYN/ACK\"];
53 client -> server [label = \"ACK\"];}")
54 (".actdiag" "actdiag -T %t -o %o -"
55 "actdiag {
56 sayHo -> ho -> hohoho
57 lane dj {
58 label = \"DJ\"
59 sayHo [label = \"Say Ho\"]; hohoho [label = \"Ho Ho Ho!\"]; }
60 lane mc { label = \"MC\"; ho [label = \"Hooooh!\"]}}")
61 (".nwdiag" "nwdiag -T %t -o %o -"
62 "nwdiag {
63 network ext {
64 address = \"10.1.2.0/24\"
65 router [address = \"10.1.2.1\"]
66 }
67 network int {
68 address = \"192.168.22.0/24\"
69 router [address = \"192.168.22.1\"]
70 websrv [address = \"192.168.22.80\"]
71 cli-1; cli-2
72 }
73 }")
74 (".rackdiag" "rackdiag -T %t -o %o -"
75 "rackdiag {
76 16U;
77 1: UPS [4U]; 5: Storage [3U]; 8: PC [2U]; 8: PC [2U];
78 }")
79 (".dot"
80 "dot -T %t -o %o"
81 "digraph {
82 graph [charset=\"utf-8\"]
83 }
84 bigraph {
85 graph [charset=\"utf-8\"]}"
86 )))
88 (defvar YaTeX-filter-special-env-alist-private nil)
89 (defvar YaTeX-filter-special-env-alist
90 (append YaTeX-filter-special-env-alist-private
91 YaTeX-filter-special-env-alist-default))
93 (defun YaTeX-filter-filter-set-conversion-flag ()
94 (let ((ovl (get 'YaTeX-filter-filter-sentinel 'overlay)))
95 (if ovl ;; When successful conversion met,
96 (progn ;; (1)Set conversion complete flag
97 (add-hook ;; (2)Add hook of seim-automatic
98 'write-file-hooks ;; update of convert to write-
99 'YaTeX-filter-update-all) ;; file hook.
100 (overlay-put ovl 'converted t)))))
102 (defun YaTeX-filter-filter-unset-conversion-flag
103 (ovl after beg end &optional length)
104 (if after (overlay-put ovl 'converted nil)))
107 (defun YaTeX-filter-pngify-sentinel (proc msg)
108 (save-excursion
109 (let ((b (process-buffer proc)) (selw (selected-window))
110 img)
111 (set-buffer b)
112 (cond
113 ((eq (process-status proc) 'run)
114 (put-text-property (point-min) (point-max) 'invisible t))
115 ((eq (process-status proc) 'exit)
116 (set-buffer b)
117 (YaTeX-popup-image
118 (YaTeX-buffer-substring
119 (get 'YaTeX-filter-pngify-sentinel 'start) (point-max))
120 b)
121 (YaTeX-filter-filter-set-conversion-flag))
122 (t
123 (set-buffer b)
124 (remove-text-properties (point-min) (point-max) '(invisible t))
125 (insert "\nProcess aborted %s\n" msg))))))
127 (defvar YaTeX-filter-pdf2png-stdout
128 (cond
129 ((YaTeX-executable-find "convert") "convert -trim %s PNG:-")
130 (t
131 "gs -dNOPAUSE -sDEVICE=png256 -sOutputFile=- -dBATCH -q -r75 %s"))
132 "Command line syntax to convert PDF file to PNG stream")
134 (defun YaTeX-filter-modified-BEGEND-regions ()
135 "Return the list of overlays which contains un-converted text."
136 (save-excursion
137 (save-restriction
138 (widen)
139 (let (r prop dest src pl (list (overlays-in (point-min) (point-max))))
140 (while list
141 (setq prop (overlay-properties (car list)))
142 (if (setq dest (plist-get prop 'filter-output))
143 (if (if (setq src (plist-get prop 'filter-source))
144 (file-newer-than-file-p src dest)
145 (and (setq pl (plist-member prop 'converted))
146 (not (plist-get pl 'converted))))
147 (setq r (cons (car list) r))))
148 (setq list (cdr list)))
149 (nconc r)
150 r))))
152 (defun YaTeX-filter-update-all ()
153 "Update all destination files from built-in source text."
154 (interactive)
155 (let ((timeout 4)
156 ans ovl (update-list (YaTeX-filter-modified-BEGEND-regions)))
157 (if update-list
158 (save-excursion
159 (save-window-excursion
160 (catch 'abort
161 (while update-list
162 (goto-char (overlay-start (setq ovl (car update-list))))
163 (or (pos-visible-in-window-p)
164 (set-window-start nil (point)))
165 (unwind-protect
166 (progn
167 (overlay-put ovl 'face 'YaTeX-on-the-fly-activated-face)
168 (message "Non-update source found: Update here: %s "
169 "Y)es N)o S)top-watching-Here A)bort")
170 (setq ans (read-char))
171 (cond
172 ((memq ans '(?Y ?y))
173 (YaTeX-filter-BEGEND)
174 (while (and (> (setq timeout (1- timeout)))
175 (eq (process-status "Filter") 'run))
176 (message "Waiting for conversion process to finish")
177 (sit-for 1)))
178 ((memq ans '(?A ?a)) (throw 'abort t))
179 ((memq ans '(?S ?s)) (delete-overlay ovl))
180 (t nil)))
181 (overlay-put ovl 'face nil))
182 (setq update-list (cdr update-list)))))))
183 ;; Write file hook should return nil
184 nil))
186 (defun YaTeX-filter-filter-sentinel (proc msg)
187 (put 'YaTeX-filter-pngify-sentinel 'start nil)
188 (let ((b (process-buffer proc))
189 (imagefile (get 'YaTeX-filter-filter-sentinel 'outfile))
190 ovl
191 (selw (selected-window)))
192 (save-excursion
193 (cond
194 ((eq (process-status proc) 'run))
195 ((eq (process-status proc) 'exit)
196 (set-buffer b)
197 (remove-images (point-min) (point-max))
198 (if (and (file-regular-p imagefile)
199 (file-readable-p imagefile))
200 (save-excursion
201 (setq buffer-read-only nil)
202 (cond
203 ((string-match "\\.\\(jpg\\|png\\)" imagefile)
204 (erase-buffer)
205 (YaTeX-popup-image imagefile b)
206 (YaTeX-filter-filter-set-conversion-flag))
207 (t ;Convert again to PNG file
208 (goto-char (point-max))
209 (insert "\nConvert Again to PNG file...\n")
210 (put 'YaTeX-filter-pngify-sentinel 'start (point))
211 (set-process-sentinel
212 (start-process
213 "Filter" b ;Safe to reuse
214 shell-file-name YaTeX-shell-command-option
215 (format YaTeX-filter-pdf2png-stdout imagefile))
216 'YaTeX-filter-pngify-sentinel)
217 (set-buffer-multibyte nil)
218 ))
219 (select-window selw)))
220 (YaTeX-preview-image-mode)
221 )
222 (t ;Other status might be an error
223 (set-buffer b)
224 (goto-char (point-max))
225 (insert (format "%s\n" (process-status proc))))))))
227 (defun YaTeX-filter-parse-filter-region (begend-info)
228 "Return the list of SpecialFilter region. If not on, return nil.
229 BEGEND-INFO is a value from the function YaTeX-in-BEGEND-p.
230 Return the alist of:
231 '((outfile $OutPutFileName)
232 (source $InputFileName) ; or nil for embeded data source
233 (cmdline $CommandLine)
234 (begin $TextRegionBeginning)
235 (end TextRegionEnd))"
236 (if begend-info
237 (let ((b (car begend-info)) (e (nth 1 begend-info))
238 delim (args (nth 2 begend-info))
239 (p (point)) openb closeb outfile source cmdline point-beg point-end)
240 (save-excursion
241 (and
242 (string-match "FILTER" args) ;easy test
243 (goto-char (car begend-info))
244 (re-search-forward
245 "FILTER\\s *{\\([^}]+\\)}" e t)
246 (setq outfile (YaTeX-match-string 1))
247 (goto-char (match-end 0))
248 (prog2 ;Step into the second brace
249 (skip-chars-forward "\t ")
250 (looking-at "{") ;Check if 2nd brace surely exists
251 (skip-chars-forward "{")
252 (skip-chars-forward "\t"))
253 (setq openb (point))
254 (condition-case nil
255 (progn (up-list 1) t)
256 (error nil))
257 (setq closeb (1- (point))
258 cmdline (YaTeX-buffer-substring openb closeb))
259 (cond
260 ((re-search-forward "^\\\\if0\\>" p t) ;; Embedded source
261 (forward-line 1)
262 (setq point-beg (if (looking-at "\\(.\\)\\1\\1") ;Triple chars
263 (progn (setq delim (YaTeX-match-string 0))
264 (forward-line 1)
265 (point))
266 (point)))
267 (re-search-forward "^\\\\fi\\>" e t)
268 (goto-char (match-beginning 0))
269 (setq point-end (if delim
270 (progn
271 (re-search-backward
272 (concat "^" (regexp-quote delim))
273 (1+ point-beg) t)
274 (match-beginning 0))
275 (point))))
276 ((re-search-forward "^\\s *%#SRC{\\(.*\\)}" e t) ; external file
277 (setq source (YaTeX-match-string 1)
278 point-beg (match-beginning 0)
279 point-end (match-end 0)))
280 (t ;; If source notation not found,
281 (let ((ovl (overlays-in b e))) ;; clear all remaining overlays
282 (while ovl
283 (delete-overlay (car ovl))
284 (setq ovl (cdr ovl)))))) ;; Return nil
286 ;; Then return all values
287 (list (cons 'outfile outfile)
288 (cons 'source source)
289 (cons 'cmdline cmdline)
290 (cons 'begin point-beg)
291 (cons 'end point-end)))))))
293 ;;debug;; (YaTeX-filter-parse-filter-region (YaTeX-in-BEGEND-p))
294 (defun YaTeX-filter-pass-to-filter (begend-info)
295 "Pass current BEGIN FILTER environment to external command."
296 (put 'YaTeX-filter-filter-sentinel 'outfile nil)
297 ;; begend-info is from YaTeX-in-BEGEND-p: (BEG END ARGS)
298 (let ((b (car begend-info)) (e (nth 1 begend-info))
299 (r (YaTeX-filter-parse-filter-region begend-info)))
300 (save-excursion
301 (if r (let*((case-fold-search t)
302 (outfile (cdr (assq 'outfile r)))
303 (source (cdr (assq 'source r)))
304 (type (cond
305 ((string-match "\\.png$" outfile) "png")
306 ((string-match "\\.svg$" outfile) "svg")
307 ((string-match "\\.tex$" outfile) "tex")
308 (t "pdf")))
309 (newcmdline (YaTeX-replace-formats
310 (cdr (assq 'cmdline r))
311 (list (cons "t" type)
312 (cons "o" outfile)
313 (cons "i" source))))
314 (text-start (cdr (assq 'begin r)))
315 (text-end (cdr (assq 'end r)))
316 (text (and (numberp text-start)
317 (numberp text-end)
318 (YaTeX-buffer-substring text-start text-end)))
319 ;;
320 ;; Now it's time to start filter process
321 ;;
322 (procbuf (YaTeX-system newcmdline "Filter" 'force))
323 (proc (get-buffer-process procbuf))
324 ;;(procbuf (get-buffer-create " *Filter*"))
325 (ovl (progn
326 (remove-overlays text-start text-end)
327 (make-overlay text-start text-end)))
328 (ovlmodhook ;hook function to reset conv-success flag
329 'YaTeX-filter-filter-unset-conversion-flag))
330 (if proc
331 (progn
332 (overlay-put ovl 'filter-output outfile)
333 (overlay-put ovl 'filter-source source)
334 (overlay-put ovl 'converted nil)
335 (overlay-put ovl 'modification-hooks (list ovlmodhook))
336 (set-process-coding-system proc 'undecided 'utf-8)
337 (set-process-sentinel proc 'YaTeX-filter-filter-sentinel)
338 (YaTeX-showup-buffer procbuf)
339 (set-buffer procbuf)
340 (setq buffer-read-only nil)
341 (erase-buffer)
342 (insert (format "Starting process `%s'...\n" newcmdline))
343 (set-marker (process-mark proc) (point-max))
344 (cond
345 (text
346 (process-send-string proc text)
347 (process-send-string proc "\n")
348 (process-send-eof proc) ;Notify stream chunk end
349 (process-send-eof proc))) ;Notify real EOF
350 (put 'YaTeX-filter-filter-sentinel 'outfile outfile)
351 (put 'YaTeX-filter-filter-sentinel 'overlay ovl))))))))
353 (defun YaTeX-insert-filter-special (filter list &optional region-p)
354 (let*((f (YaTeX-read-string-or-skip
355 "Output file(Maybe *.(pdf|png|jpg|tex)): "))
356 (insert-default-directory)
357 (cmdargs (car list))
358 (template-text (car (cdr list)))
359 (ifile (read-file-name "Data source(Default: in this buffer): " nil))
360 (in-line (string= "" ifile)))
361 (if region-p
362 (if (< (point) (mark)) (exchange-point-and-mark)))
363 (save-excursion
364 (insert (if in-line "===\n\\fi\n" "")
365 "%#END\n"
366 (cond
367 ((string-match "\\.tex$" f)
368 (format "\\input{%s}\n" (substring f 0 (match-beginning 0))))
369 ((string-match "\\.\\(pdf\\|png\\|jpe?g\\|tiff?\\)$" f)
370 (format "%%# \\includegraphics{%s}\n" f)))))
371 (and region-p (exchange-point-and-mark))
372 (insert (format "%%#BEGIN FILTER{%s}{%s}\n%s"
373 f (or cmdargs "")
374 (if in-line "\\if0\n===\n" "")))
375 (save-excursion
376 (insert (if in-line
377 (cond (template-text
378 (concat template-text
379 (or (string-match "\n$" template-text) "\n")))
380 (t "\n"))
381 (format "%%#SRC{%s}\n" ifile))))))
383 (provide 'yatexflt)
385 ; Local variables:
386 ; fill-prefix: ";;; "
387 ; paragraph-start: "^$\\| \\|;;;$"
388 ; paragraph-separate: "^$\\| \\|;;;$"
389 ; End: