5

My default shell is eshell. I just discovered iimage-mode that allows me to display images in buffers that contain some reference to an image file. Unfortunately, I doesn't seem to have any effect when it is enabled in eshell.

In any other buffer something like file:///home/rekado/Pictures/test.png is replaced with an inlined image loaded from the file test.png. In an eshell buffer, however, I cannot seem to make this work.

I tried echoing the string file:///home/rekado/Pictures/test.png, but this just results in a boring string and no pretty test image. I also made sure to use /bin/echo instead of the elisp/eshell implementation of echo, but with no success.

When I disable and reenable iimage-mode it works all right (the file name is replaced with an inline image), but that's a rather inconvenient workaround.

If there's no way to make eshell work with iimage-mode maybe there is another method to display images right in the eshell buffer?

5

Based on what happens behind the scenes when you call iimage-mode, you can define a function that takes care of displaying images for you, and have Emacs run this function every time you issue an echo command in Eshell:

(defun iimage-mode-refresh (command args)
  (when (string= command "echo")
    (let ((image-path (cons default-directory iimage-mode-image-search-path))
          file)
      (with-silent-modifications
        (save-excursion
          (eshell-previous-prompt 0) ; Start scanning from most recent prompt
                                     ; to avoid having to re-display all images.
          (dolist (pair iimage-mode-image-regex-alist)
            (while (re-search-forward (car pair) nil t)
              (when (and (setq file (match-string (cdr pair)))
                         (setq file (locate-file file image-path)))
                (add-text-properties (match-beginning 0) (match-end 0)
                                     `(display ,(create-image file)
                                               modification-hooks
                                               (iimage-modification-hook)))))))))))

(add-hook 'eshell-named-command-hook 'iimage-mode-refresh)

The main difference between this function and the function that gets run when you enable iimage-mode (iimage-mode-buffer) is that it does not check the whole buffer for image references. Instead, it starts scanning from the most recent prompt, which means that calling the function does not become more expensive as the *eshell* buffer grows in size. Each invocation of the function will cause only a single additional image (i.e., the most recent image you requested) to be displayed.

Note that existing images stay visible, i.e., they are not "reset" to strings representing file paths.

  • 1
    Thanks, this doesn't look bad. I think it would be even better to turn this into a separate eshell command instead of a hook that's linked to the execution of echo. – rekado Nov 12 '14 at 14:56
  • 1
    It's a pity that iimage.el doesn't expose some other function that we could cleanly reuse. As it stands, iimage-mode-refresh is almost a complete copy of iimage-mode-buffer. – rekado Nov 12 '14 at 14:59
  • @rekado "I think it would be even better...": You might want to consider adding your own answer with a modified version of the code. It sounds like you're up to the task. Also, we should delete the first four comments, as the information they contain has become misleading. – itsjeyd Nov 12 '14 at 16:37
  • I just posted an answer in which eshell/cat is extended to work with images. – rekado Mar 2 '15 at 15:06
2

Based on itsjeyd's answer I advised eshell/cat to display images when an argument is the filename of an image file supported by iimage-mode.

(defun my/iimage-mode-refresh--eshell/cat (orig-fun &rest args)
  "Display image when using cat on it."
  (let ((image-path (cons default-directory iimage-mode-image-search-path)))
    (dolist (arg args)
      (let ((imagep nil)
            file)
        (with-silent-modifications
          (save-excursion
            (dolist (pair iimage-mode-image-regex-alist)
              (when (and (not imagep)
                         (string-match (car pair) arg)
                         (setq file (match-string (cdr pair) arg))
                         (setq file (locate-file file image-path)))
                (setq imagep t)
                (add-text-properties 0 (length arg)
                                     `(display ,(create-image file)
                                               modification-hooks
                                               (iimage-modification-hook))
                                     arg)
                (eshell-buffered-print arg)
                (eshell-flush)))))
        (when (not imagep)
          (apply orig-fun (list arg)))))
    (eshell-flush)))

(advice-add 'eshell/cat :around #'my/iimage-mode-refresh--eshell/cat)

This allows me to display images right in the eshell buffer and to concatenate images and text alike. There's probably a more elegant way to do this (and a safer way in case iimage-mode is not enabled), but I'll just leave it like this for now until it bites me.

0

I have the similar problem at markdown-mode ,when I want to display images in xxx.md alive. I just glance at the iimage.el , And I find out (iimage-mode-buffer iimage-mode) this works fine for me.

(defun my-md-screenshot ()
   "Take a screenshot into a time stamped unique-named file in the
same directory as the org-buffer and insert a link to this file."
(interactive)
(setq filename
    (concat
     (make-temp-name
      (concat (file-name-base)
              "_"
              (format-time-string "%Y%m%d_%H%M%S_")) ) ".png"))
(call-process-shell-command "screencapture" nil nil nil
                          (concat " -i ~/public/img/" filename))
(insert (concat "![image](/public/img/" filename ")"))
(iimage-mode-buffer iimage-mode)
)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.