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 146 147 148 149 150 151
|
;;; iimage.el --- Inline image minor mode. -*- lexical-binding: t -*-
;; Copyright (C) 2004-2025 Free Software Foundation, Inc.
;; Author: KOSEKI Yoshinori <kose@meadowy.org>
;; Maintainer: emacs-devel@gnu.org
;; Keywords: multimedia
;; This file is part of GNU Emacs.
;; GNU Emacs 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.
;; GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; Iimage is a minor mode that displays images, when image-filename
;; exists in the buffer.
;;
;; ** Display images in *Info* buffer.
;;
;; (add-hook 'info-mode-hook 'iimage-mode)
;;
;; .texinfo: @file{file://foo.png}
;; .info: `file://foo.png'
;;
;; ** Display images in Wiki buffer.
;;
;; (add-hook 'wiki-mode-hook 'iimage-mode)
;;
;; wiki-file: [[foo.png]]
;;; Code:
(eval-when-compile
(require 'image-file))
(defgroup iimage nil
"Support for inline images."
:version "22.1"
:group 'image)
(defcustom iimage-mode-image-search-path nil
"List of directories to search for image files for `iimage-mode'."
:type '(choice (const nil) (repeat directory)))
(defvar iimage-mode-image-filename-regex
(concat "[-+./_0-9a-zA-Z]+\\."
(regexp-opt (nconc (mapcar #'upcase
image-file-name-extensions)
image-file-name-extensions)
t)))
(defcustom iimage-mode-image-regex-alist
`((,(concat "\\(`?file://\\|\\[\\[\\|<\\|`\\)?"
"\\(" iimage-mode-image-filename-regex "\\)"
"\\(\\]\\]\\|>\\|'\\)?") . 2))
"Alist that specifies how to detect filenames of images to be displayed inline.
The value should be an alist whose elements have the form
(REGEXP . NUM)
where REGEXP is a regular expression to search buffer text for what
might be a specification of an inline image, and NUM is the number
of a parenthesized sub-expression of REGEXP which gives the name of
the image file to look up.
Examples of image filename patterns to match:
file://foo.png
\\=`file://foo.png\\='
\\[\\[foo.gif]]
<foo.png>
foo.JPG"
:type '(alist :key-type regexp :value-type integer))
(defvar-keymap iimage-mode-map
:doc "Keymap used in `iimage-mode'."
"C-l" #'iimage-recenter)
(defun iimage-recenter (&optional arg)
"Re-draw images and recenter."
(interactive "P")
(iimage-mode-buffer nil)
(iimage-mode-buffer t)
(recenter-top-bottom arg))
(defun turn-off-iimage-mode ()
"Unconditionally turn off iimage mode."
(interactive)
(iimage-mode 0))
(defun iimage-modification-hook (beg end)
"Remove display property if a display region BEG..END is modified."
;;(debug-print "ii1 begin %d, end %d\n" beg end)
(let ((inhibit-modification-hooks t)
(beg (previous-single-property-change end 'display
nil (line-beginning-position)))
(end (next-single-property-change beg 'display
nil (line-end-position))))
(when (and beg end (plist-get (text-properties-at beg) 'display))
;;(debug-print "ii2 begin %d, end %d\n" beg end)
(remove-text-properties beg end
'(display nil modification-hooks nil)))))
(defun iimage-mode-buffer (arg)
"Display images if ARG is non-nil, undisplay them otherwise."
(let ((image-path (cons default-directory iimage-mode-image-search-path))
(edges (window-inside-pixel-edges (get-buffer-window)))
file)
(with-silent-modifications
(save-excursion
(dolist (pair iimage-mode-image-regex-alist)
(goto-char (point-min))
(while (re-search-forward (car pair) nil t)
(when (and (setq file (match-string (cdr pair)))
(setq file (locate-file file image-path)))
;; FIXME: we don't mark our images, so we can't reliably
;; remove them either (we may leave some of ours, and we
;; may remove other packages's display properties).
(if arg
(add-text-properties
(match-beginning 0) (match-end 0)
`(display
,(create-image file nil nil
:max-width (- (nth 2 edges) (nth 0 edges))
:max-height (- (nth 3 edges) (nth 1 edges)))
keymap ,image-map
context-menu-functions (image-context-menu)
modification-hooks
(iimage-modification-hook)))
(remove-list-of-text-properties
(match-beginning 0) (match-end 0)
'(display modification-hooks))))))))))
;;;###autoload
(define-minor-mode iimage-mode nil
:group 'iimage :lighter " iImg" :keymap iimage-mode-map
(iimage-mode-buffer iimage-mode))
(provide 'iimage)
;;; iimage.el ends here
|