|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
;; esvg-show.el. -*- lexical-binding: nil; -*-
;; This file:
;; https://anggtwu.net/elisp/esvg-show.el.html
;; https://anggtwu.net/elisp/esvg-show.el
;; (find-angg "elisp/esvg-show.el")
;; See: https://anggtwu.net/2026-eepitch-svg.html
;; Author: Eduardo Ochs <eduardoochs@gmail.com>
;; Version: 2026aug14
;;
;; This is the lowest-level file of esvg - edrx's (REPL for) SVG.
;;
;; Note that svg.el comes with an executable example in its comments,
;; but it is a bit tricky to run because it inserts an SVG image at the
;; end of svg.el itself... see (and maybe try):
;;
;; (find-efile "svg.el" "Here are some usage examples:")
;; (find-efile "svg.el" "(goto-char (point-max))")
;;
;; Now try this test:
;;
;; (load (buffer-file-name))
;; (setq svg (svg-create 400 400 :stroke "orange" :stroke-width 5))
;; (show-svg-pp-xml)
;; (svg-rectangle svg 100 100 200 100 :fill "red" :id "rect1")
;; (svg-rectangle svg 120 120 200 100 :fill "green" :id "rect2")
;; (svg-rectangle svg 110 100 200 100 :fill "red" :id "rect1")
;; (svg-rectangle svg 100 100 200 100 :fill "red" :id "rect1")
;; (show-svg-pp-xml)
;;
;; It creates a 4-window setting like this,
;;
;; ____________________________
;; | | |
;; | | SVG (image) |
;; | |_______________|
;; | This | |
;; | file | SVG as Lisp |
;; | |_______________|
;; | | |
;; | | SVG as XML |
;; |____________|_______________|
;;
;; and the calls to `svg-rectangle' update the SVG image, but not the
;; windows with in which the SVG object is shown as Lisp and as XML.
;;
;; Index:
;; «.esvg-xml-to-string» (to "esvg-xml-to-string")
;; «.find-xml-indent» (to "find-xml-indent")
;; «.find-4a» (to "find-4a")
;; «.show-svg-1» (to "show-svg-1")
;; «.show-svg» (to "show-svg")
;; Esvg is built on top of eev, and it implements
;; alternatives for some functions in svg.el.
(require 'eev-load) ; See: (find-eev-install-intro "0.2. Loading")
(require 'svg) ; See: (find-efile "svg.el")
(defvar svg) ; The `show-*' functions use this variable
;; «esvg-xml-to-string» (to ".esvg-xml-to-string")
;; Tests: (esvg-xml-to-string (svg-create 1 2))
;; (esvg-xml-to-string '(svg))
;; (esvg-xml-to-string '(svg nil))
;; (esvg-xml-to-string '(svg nil (rect)))
;; (esvg-xml-to-string '(svg ((w . 1) (h . 2)) (rect)))
;; (esvg-xml-to-string '(svg ((w . 1) (h . 2)) (rect) (rect)))
;; (esvg-xml-to-string '(svg ((w . 1) (h . 2)) (rect nil)))
;; (esvg-xml-to-string '(svg ((w . 1) (h . 2)) (rect nil (subrect))))
;; (esvg-xml-to-string '(svg ((w . 1) (h . 2)) (foo ((a . 3) (b . 4)) (bar))))
;; (esvg-xml-to-string "<svg></svg>\n\n")
;;
(defun esvg-xml-to-string (o)
"Convert O to a multi-line string.
If O is string, treat it as XML, split it into lines, and indent it.
If O is a list convert it to XML first by using `esvg--svg-print',
that is a wrapper around `svg-print'.
This function is used by `show-xml-1'."
(if (not (stringp o))
(setq o (esvg--svg-print o)))
(setq o (replace-regexp-in-string "[ \t\n]+" " " o))
(setq o (replace-regexp-in-string ">[ \t\n]*<" ">\n<" o))
(setq o (esvg--xml-indent o))
(setq o (replace-regexp-in-string "[ \t\n]*\\'" "" o)))
;; Tests: (esvg--svg-print (svg-create 1 2))
;; (esvg--svg-print '(svg nil))
;; (esvg--svg-print '(svg ((w . 1) (h . 2))))
;; (esvg--svg-print '(svg ((w . 1) (h . 2)) (rect)))
;; See: (find-efunction 'svg-print)
(defun esvg--svg-print (o)
"An internal function used by `esvg-xml-to-string'."
(with-temp-buffer
(svg-print o)
(buffer-string)))
;; Test: (esvg--xml-indent "<a>\n<b>\n</b>\n</a>")
(defun esvg--xml-indent (xmlstr)
"An internal function used by `esvg-xml-to-string'."
(with-temp-buffer
(insert xmlstr)
(xml-mode)
(indent-region (point-min) (point-max))
(buffer-string)))
;; «find-xml-indent» (to ".find-xml-indent")
(defun esvg-xml-at-point ()
"If the point is on an SVG image then return its XML."
(plist-get (cdr (get-text-property (point) 'display)) :data))
(defun esvg-xml-at-point-or-region ()
(or (esvg-xml-at-point)
(buffer-substring (point) (mark))))
(defun find-xml-indent (&optional s)
"Display the XML of an SVG image in a temporary buffer, in indented form.
This function is meant to be used interactively. If we call it with the
point on an SVG image, it extracts the XML from the `display' text
property of the image at point; if there is no SVG image at point it
uses the region."
(interactive)
(find-estring
(esvg-xml-to-string
(or s (esvg-xml-at-point-or-region)))))
;; «find-4a» (to ".find-4a")
;; Based on: (find-efunction 'find-3a)
;; See: (find-multiwindow-intro "3. High-level words")
;; Test: (find-4a nil nil nil nil)
(defun find-4a (a b c d) (find-wset "13_o22+_o_o_o" a b c d))
;; «show-svg-1» (to ".show-svg-1")
;; Tests: (show-svg)
;; (show-svg-pp)
;; (show-svg-pp-xml)
;;
(defun show-svg-1 ()
(find-ebuffer "*svg*")
(delete-region (point-min) (point-max))
(if svg (svg-insert-image svg))
(goto-char (point-min))
(setq cursor-type nil))
(defun show-pp-1 ()
(let ((ee-buffer-name (or ee-buffer-name "*svg-pp*")))
(find-epp svg)))
(defun show-xml-1 ()
(let ((ee-buffer-name (or ee-buffer-name "*svg-xml*")))
(find-estring (esvg-xml-to-string svg))))
;; «show-svg» (to ".show-svg")
;; The top-level functions.
;; See the test at the top of this file.
;;
(defun show-svg ()
(interactive)
(find-2a nil '(show-svg-1)))
(defun show-svg-pp ()
(interactive)
(find-3a nil '(show-svg-1) '(show-pp-1)))
(defun show-svg-pp-xml ()
(interactive)
(find-4a nil '(show-svg-1) '(show-pp-1) '(show-xml-1)))
(defun show-pp-xml ()
(interactive)
(find-3a nil '(show-pp-1) '(show-xml-1)))
(defun show-pp ()
(interactive)
(find-2a nil '(show-pp-1)))
(provide 'esvg-show)
;; Local Variables:
;; coding: utf-8-unix
;; End: