yatex

annotate yatexflt.el @ 556:fbb636ff0fe3

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