3
votes

I've just discovered the shr package in emacs 24.5.1

i.e.

C-x C-f anyfile.html
M-x shr-render-buffer

Looks really good - just what I was after

Can I automate emacs to call shr-render-buffer when I open any .htm or .html file?

UPDATE

I've tried adding the following to my .emacs:

(add-to-list 'auto-mode-alist '("[.]htm$" . shr-render-buffer))
(add-to-list 'auto-mode-alist '("[.]html$" . shr-render-buffer))

but I get the error:

File mode specification error: (void-function shr-render-buffer)

The html file then gets opened in Fundamental mode and it looks even worse than HTML mode

2
Google: "auto-mode-alist" emacslawlist
I could be wrong here, but i think auto-mode-alist is used to associate a file ext with a mode. shr doesn't seem to be a mode, shr-render-buffer is a function that has to be applied to a buffer once its been loaded. The mode for .htm/.html is HTML by default, but this doesn't try and do any nice formatting like shrbph
What yuo want is relatively easy to do. However, before I write this up, I just wanted to check that you are aware of eww (which uses shr IIRC). It is also part of 34.5 and will likely provide an even nicer experience. You can easily use it with brows-rul so that if you view an html file it is rendered and if you edit it you get html-mode (or whatever html editing mode you prefer)Tim X
eww-open-file seems to be same as shr-render-buffer in term of what I see. I note that the mode is eww though, so maybe I can use auto-mode-alist in this instance?bph
Here is a link to a related thread and solution that may suit your needs: emacs.stackexchange.com/a/19858/2287lawlist

2 Answers

2
votes

It seems you want to run the function shr-render-buffer automatically once a html file is opened. As you said, the mode for .htm/.html is html-mode by default, you can add the function invocation to the html-mode-hook, such as:

(add-hook 'html-mode-hook '(lambda() (shr-render-buffer (current-buffer))))

As @lawlist pointed, put it after (require 'shr).

1
votes

As this is emacs, the hardest part of doing what you want is deciding on what is the best approach. This largely depends on personal taste/workflows. I would highly recommend looking at the browse-url package in more detail. One thing I use is a function which allows me to switch between using eww or my default system browser - this means I can easily render web content either in emacs or in chrome/safari/whatever.

Some years ago, I wrote a utility which would allow me to view a number of different file formats, including rendered html, in emacs. I rarely use this now as doc-view has pretty much replaced most of this functionality and is much better. However, it does show how you can use defadvice to modify the view-file function so that id does different things depending on the file type. Note that as this is old emacs code and emacs has improved, there are probably better ways of doing this now. I also know that the 'advice' stuff has been re-worked, but this legacy stuff still works OK. Should get you started. Note that the functionality for MS doc, docx, pdf etc relies on external executables.

My preferred workflow would be to write a function which allows me to reset the browse-url-browser-function to either eww-browse-url or browse-url-default-browser and bind that to a key. I can then choose to display the html in emacs or the external browser and leverage of all the work already done in browse-url.

(require 'custom)
(require 'browse-url)

;; make-temp-file is part of apel prior to emacs 22
;;(static-when (= emacs-major-version 21)
;;  (require 'poe))

(defgroup txutils nil
  "Customize group for txutils."
  :prefix "txutils-"
  :group 'External)

(defcustom txutils-convert-alist
  '( ;; MS Word
    ("\\.\\(?:DOC\\|doc\\)$"     doc  "/usr/bin/wvText"    nil nil nil nil nil)
    ;; PDF
    ("\\.\\(?:PDF\\|pdf\\)$"     pdf  "/usr/bin/pdftotext" nil nil nil nil nil)
    ;; PostScript
    ("\\.\\(?:PS\\|ps\\)$"       ps   "/usr/bin/pstotext"  "-output" t nil nil nil)
    ;; MS PowerPoint
    ("\\.\\(?:PPT\\|ppt\\)$"     ppt  "/usr/bin/ppthtml"   nil nil nil t t))

  "*Association for program convertion.

Each element has the following form:

(REGEXP SYMBOL CONVERTER SWITCHES INVERT REDIRECT-INPUT REDIRECT-OUTPUT HTML-OUTPUT)

Where:

REGEXP             is a regexp to match file type to convert.

SYMBOL             is a symbol to designate the fyle type.

CONVERTER          is a program to convert the fyle type to text or HTML.

SWITCHES           is a string which gives command line switches for the conversion
program. Nil means there are no switches needed.

INVERT             indicates if input and output program option is to be
inverted or not.  Non-nil means to invert, that is, output
option first then input option.  Nil means do not invert,
that is, input option first then output option.

REDIRECT-INPUT indicates to use < to direct input from the input
file. This is useful for utilities which accept input
from stdin rather than a file.

REDIRECT-OUTPUT indicates to use > to direct output to the output
file. This is useful for utilities that only send output to
stdout.

HTML-OUTPUT    Indicates the conversion program creates HTML output
rather than plain text."

  :type '(repeat
          (list :tag "Convertion"
                (regexp  :tag "File Type Regexp")
                (symbol  :tag "File Type Symbol")
                (string  :tag "Converter")
                (choice  :menu-tag "Output Option"
                         :tag "Output Option"
                         (const :tag "None" nil)
                         string)
                (boolean :tag "Invert I/O Option")
                (boolean :tag "Redirect Standard Input")
                (boolean :tag "Redirect Standard Output")
                (boolean :tag "HTML Output")))
  :group 'txutils)

(defun txutils-run-command (cmd &optional output-buffer)
  "Execute shell command with arguments, putting output in buffer."
  (= 0 (shell-command cmd (if output-buffer
                              output-buffer
                            "*txutils-output*")
                      (if output-buffer
                          "*txutils-output*"))))

(defun txutils-quote-expand-file-name (file-name)
  "Expand file name and quote special chars if required."
  (shell-quote-argument (expand-file-name file-name)))

(defun txutils-file-alist (file-name)
  "Return alist associated with file of this type."
  (let ((al txutils-convert-alist))
    (while (and al
                (not (string-match (caar al) file-name)))
      (setq al (cdr al)))
    (if al
        (cdar al)
      nil)))

(defun txutils-make-temp-name (orig-name type-alist)
  "Create a temp file name from original file name"
  (make-temp-file (file-name-sans-extension
                   (file-name-nondirectory orig-name)) nil
                   (if (nth 7 type-alist)
                       ".html"
                     ".txt")))

(defun txutils-build-cmd (input-file output-file type-alist)
  "Create the command string from conversion alist."
  (let ((f1 (if (nth 3 type-alist)
                output-file
              input-file))
        (f2 (if (nth 3 type-alist)
                input-file
              output-file)))
    (concat
     (nth 1 type-alist)
     (if (nth 2 type-alist)               ; Add cmd line switches
         (concat " " (nth 2 type-alist)))
     (if (nth 4 type-alist)          ; redirect input (which may be output
         (concat " < " f1)           ; if arguments are inverted!)
       (concat " " f1))
     (if (nth 5 type-alist)          ; redirect output (see above comment)
         (concat " > " f2)
       (concat " " f2)))))

(defun txutils-do-file-conversion (file-name)
  "Based on file extension, convert file to text. Return name of text file"
  (interactive "fFile to convert: ")
  (let ((f-alist (txutils-file-alist file-name))
        output-file)
    (when f-alist
      (message "Performing file conversion for %s." file-name)
      (setq output-file (txutils-make-temp-name file-name f-alist))
      (message "Command: %s" (txutils-build-cmd file-name output-file f-alist))
      (if (txutils-run-command
           (txutils-build-cmd (txutils-quote-expand-file-name file-name)
                              (txutils-quote-expand-file-name
                               output-file) f-alist))
          output-file
        file-name))))

(defadvice view-file (around txutils pre act comp)
  "Perform file conversion or call web browser to view contents of file."
  (let ((file-arg (ad-get-arg 0)))
    (if (txutils-file-alist file-arg)
        (ad-set-arg 0 (txutils-do-file-conversion file-arg)))
    (if (string-match "\\.\\(?:HTML?\\|html?\\)$" (ad-get-arg 0))
        (browse-url-of-file (ad-get-arg 0))
      ad-do-it)))

(provide 'init-text-convert)