| 1 | ;;; iimage.el --- Inline image minor mode. |
| 2 | |
| 3 | ;; Copyright (C) 2004-2014 Free Software Foundation, Inc. |
| 4 | |
| 5 | ;; Author: KOSEKI Yoshinori <kose@meadowy.org> |
| 6 | ;; Maintainer: KOSEKI Yoshinori <kose@meadowy.org> |
| 7 | ;; Keywords: multimedia |
| 8 | |
| 9 | ;; This file is part of GNU Emacs. |
| 10 | |
| 11 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
| 12 | ;; it under the terms of the GNU General Public License as published by |
| 13 | ;; the Free Software Foundation, either version 3 of the License, or |
| 14 | ;; (at your option) any later version. |
| 15 | |
| 16 | ;; GNU Emacs is distributed in the hope that it will be useful, |
| 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 19 | ;; GNU General Public License for more details. |
| 20 | |
| 21 | ;; You should have received a copy of the GNU General Public License |
| 22 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
| 23 | |
| 24 | ;;; Commentary: |
| 25 | |
| 26 | ;; Iimage is a minor mode that displays images, when image-filename |
| 27 | ;; exists in the buffer. |
| 28 | ;; |
| 29 | ;; ** Display images in *Info* buffer. |
| 30 | ;; |
| 31 | ;; (add-hook 'info-mode-hook 'iimage-mode) |
| 32 | ;; |
| 33 | ;; .texinfo: @file{file://foo.png} |
| 34 | ;; .info: `file://foo.png' |
| 35 | ;; |
| 36 | ;; ** Display images in Wiki buffer. |
| 37 | ;; |
| 38 | ;; (add-hook 'wiki-mode-hook 'iimage-mode) |
| 39 | ;; |
| 40 | ;; wiki-file: [[foo.png]] |
| 41 | |
| 42 | ;;; Code: |
| 43 | |
| 44 | (eval-when-compile |
| 45 | (require 'image-file)) |
| 46 | |
| 47 | (defgroup iimage nil |
| 48 | "Support for inline images." |
| 49 | :version "22.1" |
| 50 | :group 'image) |
| 51 | |
| 52 | (defcustom iimage-mode-image-search-path nil |
| 53 | "List of directories to search for image files for iimage-mode." |
| 54 | :type '(choice (const nil) (repeat directory)) |
| 55 | :group 'iimage) |
| 56 | |
| 57 | (defvar iimage-mode-image-filename-regex |
| 58 | (concat "[-+./_0-9a-zA-Z]+\\." |
| 59 | (regexp-opt (nconc (mapcar #'upcase |
| 60 | image-file-name-extensions) |
| 61 | image-file-name-extensions) |
| 62 | t))) |
| 63 | |
| 64 | (defcustom iimage-mode-image-regex-alist |
| 65 | `((,(concat "\\(`?file://\\|\\[\\[\\|<\\|`\\)?" |
| 66 | "\\(" iimage-mode-image-filename-regex "\\)" |
| 67 | "\\(\\]\\]\\|>\\|'\\)?") . 2)) |
| 68 | "Alist of filename REGEXP vs NUM. |
| 69 | Each element looks like (REGEXP . NUM). |
| 70 | NUM specifies which parenthesized expression in the regexp. |
| 71 | |
| 72 | Examples of image filename patterns to match: |
| 73 | file://foo.png |
| 74 | `file://foo.png' |
| 75 | \\[\\[foo.gif]] |
| 76 | <foo.png> |
| 77 | foo.JPG |
| 78 | " |
| 79 | :type '(alist :key-type regexp :value-type integer) |
| 80 | :group 'iimage) |
| 81 | |
| 82 | (defvar iimage-mode-map |
| 83 | (let ((map (make-sparse-keymap))) |
| 84 | (define-key map "\C-l" 'iimage-recenter) |
| 85 | map) |
| 86 | "Keymap used in `iimage-mode'.") |
| 87 | |
| 88 | (defun iimage-recenter (&optional arg) |
| 89 | "Re-draw images and recenter." |
| 90 | (interactive "P") |
| 91 | (iimage-mode-buffer nil) |
| 92 | (iimage-mode-buffer t) |
| 93 | (recenter arg)) |
| 94 | |
| 95 | ;;;###autoload |
| 96 | (define-obsolete-function-alias 'turn-on-iimage-mode 'iimage-mode "24.1") |
| 97 | |
| 98 | (defun turn-off-iimage-mode () |
| 99 | "Unconditionally turn off iimage mode." |
| 100 | (interactive) |
| 101 | (iimage-mode 0)) |
| 102 | |
| 103 | (defun iimage-modification-hook (beg end) |
| 104 | "Remove display property if a display region is modified." |
| 105 | ;;(debug-print "ii1 begin %d, end %d\n" beg end) |
| 106 | (let ((inhibit-modification-hooks t) |
| 107 | (beg (previous-single-property-change end 'display |
| 108 | nil (line-beginning-position))) |
| 109 | (end (next-single-property-change beg 'display |
| 110 | nil (line-end-position)))) |
| 111 | (when (and beg end (plist-get (text-properties-at beg) 'display)) |
| 112 | ;;(debug-print "ii2 begin %d, end %d\n" beg end) |
| 113 | (remove-text-properties beg end |
| 114 | '(display nil modification-hooks nil))))) |
| 115 | |
| 116 | (defun iimage-mode-buffer (arg) |
| 117 | "Display images if ARG is non-nil, undisplay them otherwise." |
| 118 | (let ((image-path (cons default-directory iimage-mode-image-search-path)) |
| 119 | file) |
| 120 | (with-silent-modifications |
| 121 | (save-excursion |
| 122 | (goto-char (point-min)) |
| 123 | (dolist (pair iimage-mode-image-regex-alist) |
| 124 | (while (re-search-forward (car pair) nil t) |
| 125 | (when (and (setq file (match-string (cdr pair))) |
| 126 | (setq file (locate-file file image-path))) |
| 127 | ;; FIXME: we don't mark our images, so we can't reliably |
| 128 | ;; remove them either (we may leave some of ours, and we |
| 129 | ;; may remove other packages's display properties). |
| 130 | (if arg |
| 131 | (add-text-properties (match-beginning 0) (match-end 0) |
| 132 | `(display ,(create-image file) |
| 133 | modification-hooks |
| 134 | (iimage-modification-hook))) |
| 135 | (remove-text-properties (match-beginning 0) (match-end 0) |
| 136 | '(display modification-hooks)))))))))) |
| 137 | |
| 138 | ;;;###autoload |
| 139 | (define-minor-mode iimage-mode nil |
| 140 | :group 'iimage :lighter " iImg" :keymap iimage-mode-map |
| 141 | (iimage-mode-buffer iimage-mode)) |
| 142 | |
| 143 | (provide 'iimage) |
| 144 | |
| 145 | ;;; iimage.el ends here |