nXhtml: tame your rhtml files

August 31, 2007 – 12:21 am

I personally use Emacs as an IDE to develop rails project. Equipped with emacs-rails, it becomes a powerful IDE for rails developing.

However, you may noticed, it doesn’t have full support for rhtml files. You can use html-mode to edit rhtml files, it is already good enough. But is is of course not as good as other wonderful modes(e.g. ruby-mode) Emacs supplied.

Other choices is mmm-mode, two-mode-mode or some similar things. But it is a little complicated to config while the results is not very impressing.

There’s also a custom-made mode for rhtml files in Rinari: rhtml-mode. It might be good. Bug I guess there’s something wrong with the code. Emacs may become slow when I turn on this mode: a latency can be felt even to move the cursor up and down.

I still use the plain old html-mode to edit those rhtml files, until I finally find the godsends nXhtml package. It has a nxhtml-mode which can recognize plenty of embedded fragment including javascript, php and, of course, ruby, etc.

It is really an amazing package! And the installation is very simple. Just download the latest nXhtml zip package. Unzip it and load the autostart.el file in your Emacs.

However, as an Emacs geek, I always want to configure it to my own style. So here comes my configuration for nXhtml to edit rhtml files:

(load "~/emacs/packages/nxml/autostart.el")
(add-to-list 'auto-mode-alist
             '("\\.rhtml$" . kid-rhtml-mode))
;; only special background in submode
(setq mumamo-chunk-coloring 'submode-colored)
(setq nxhtml-skip-welcome t)
;; do not turn on rng-validate-mode automatically, I don't like
;; the anoying red underlines
(setq rng-nxml-auto-validate-flag nil)
;; force to load another css-mode, the css-mode in nxml package
;; seems failed to load under my Emacs 23
(let ((load-path (cons "~/emacs/extension/"
  (require 'css-mode))
(defun kid-rhtml-mode ()
  ;; I don't use cua-mode, but nxhtml always complains. So, OK, let's
  ;; define this dummy variable
  (make-local-variable 'cua-inhibit-cua-keys)
  (setq mumamo-current-chunk-family '("eRuby nXhtml Family" nxhtml-mode
  (rails-minor-mode t)
  (auto-fill-mode -1)
  (setq tab-width 2)
  (setq indent-tabs-mode nil))

You can see in the screenshot the nxhtml-mode recognize both ERB fragment and javascript fragment. It can also handle css fragment if you have proper css-mode installed(nxml comes with a css-mode, but it refuses to load with my Emacs 23). Wonderful! :D

  1. 15 Responses to “nXhtml: tame your rhtml files”

  2. Hi,the nxhtml helps a lot.

    But seems there is some problem,I found a line “File mode specification error: (void-function rails-minor-mode)” in the *Message* buffer,why?

    thanks for the post.

    By eastwoodsz on Nov 17, 2007

  3. to eastwoodsz :
    Hi! Maybe you didn’t install the emacs-rails extension. Then just remove or comment the 30-th line in the example above:

    (rails-minor-mode t)

    By pluskid on Nov 17, 2007

  4. Thanks Pluskid for your kindly reply!

    Yes I finally found the reason,and now installed emacs-rails extension,and ecb/cedet,it seems wonderful to develop rails application with Emacs now!

    By eastwoodsz on Nov 20, 2007

  5. You are welcome! Hope you enjoy it! :)

    By pluskid on Nov 20, 2007

  6. pluskid你好,请问yasnippet可以和nxhtml-mode一起用吗?我把yasnippet里的html-mode复制成nxhtml-mode之后,也只能在单独的nxhtml-mode中使用,而不能在其自动识别的复合模式中使用。还望指教,为谢。

    By transtone on Jul 8, 2008

  7. @transtone,
    你是指在 nxhtml-mode 的多模式下?比如,编辑 js 或者 css 的时候?这个我倒是还没有尝试过,不知道它是使用什么方式切换 major-mode 的,也许这影响到 YASnippet 的 minor-mode 的开启了。你如果在 mode-line 上没有看到 YAS 的字样的话应该是 minor-mode 没能自动打开。

    By pluskid on Jul 8, 2008

  8. nxhtml自动识别的话就是多模式了。在mode-line是有yas字样的,应该yas的主模式是开启的。mode-line里的nxhtml是显示成 nXhtml/nxhtml 式样,这种情况下的tab是无法调用yas的。不论是在css, js 还是 html 代码中都是一样。并且我手动打开 yas/minor-mode, 也还是无法识别,是不是mode的名字引起的?

    By transtone on Jul 9, 2008

  9. @transtone,
    如果它的 mode-name 是 nXhtml/nxhtml-mode 的话估计有问题……你试试看 C-h k 再按 TAB 键看看 TAB 是不是被绑定到 yas/expand 上了?

    By pluskid on Jul 9, 2008

  10. 没有绑定给yasnippet:

    runs the command indent-for-tab-command
      which is an interactive compiled Lisp function in `indent.el'.
    It is bound to .
    (indent-for-tab-command &optional arg)

    要是yasnippet能自动插入到这种复合模式中工作那就完美了。nxhtml-mode自带的自动完成功能不怎么好用,好像是用的是snippet.el,因为我对elisp很不熟,只好到处求助,可google出来的yasnippet相关信息太少了。如果你也很喜欢nxhtml-mode的话,能不能和它的作者沟通一下,把yasnippet作为它的默认tab complete?

    By transtone on Jul 9, 2008

  11. @transtone,
    汗……你把最关键的信息去掉了,我主要是想知道那里是 TAB 还是 。如果是后者的话,应该好解决,试试:

    (add-hook 'nxhtml-mode-hook
              '(lambda ()
                 (local-set-key [tab] 'yas/expand)))

    恩,还有诸如 Emacs 的 rails 支持等好像都是用的 snippet ,等我有时间的时候也是得考虑一下和这些作者沟通一下,哈哈! ^_^ 多谢支持!

    By pluskid on Jul 9, 2008

  12. 不是我去掉的,是输入到Comment后自动去掉的。

    <tab> runs the command indent-for-tab-command
      which is an interactive compiled Lisp function in `indent.el'.
    It is bound to .
    (indent-for-tab-command &optional arg)
    Indent line in proper way for current major mode or insert a tab.
    Depending on `tab-always-indent', either insert a tab or indent.
    If initial point was within line's indentation, position after
    the indentation.  Else stay at same point in text.
    The function actually called to indent is determined by the value of

    By transtone on Jul 9, 2008

  13. 添加了那个绑定,但还是无效。
    都把这变成论坛了 :) 下面是C-h m 后的全部信息:

    Enabled minor modes: Auto-Compression Column-Number Display-Time
    Encoded-Kbd File-Name-Shadow Font-Lock Global-Font-Lock Hs Icomplete
    Line-Number Menu-Bar Mlinks Mouse-Wheel Nxhtml Outline Shell-Dirtrack
    Show-Paren Tabbar Tooltip Transient-Mark Unify-8859-On-Encoding
    Utf-Translate-Cjk Yas/Minor
    (Information about these minor modes follows the major mode info.)
    nXhtml/nxhtml mode:
    Major mode for editing XHTML documents.
    It is based on `nxml-mode' and adds some features that are useful
    when editing XHTML files.
    To see an overview in html format do M-x nxhtml-overview.
    * Note: Please observe that when loading nXhtml some file
      associations are done, see `nxhtml-auto-mode-alist'.
    The nXhtml menu is added by this mode (or actually the minor
    mode `nxhtml-minor-mode') and gives quick access and an overview
    of some other important features. These includes:
    - multiple major modes, see `define-mumamo-multi-major-mode'
    - easy uploading and viewing of files, see for example
    - validation in XHTML part for php etc, see
      `nxhtml-validation-header-mode' (you probably also want to know about
      `nxhtml-toggle-visible-warnings' for this!)
    - converting of html to xhtml, see `tidy-buffer'
    The XML menu contains functionality added by `nxml-mode' (on
    which this major mode is based).  There is also a popup menu
    added to the [apps] key.
    The most important features are probably completion and
    validation, which is inherited from `nxml-mode' with some small
    addtions.  In very many situation you can use completion. To
    access it type . Completion has been enhanced in
    the following way:
    - If region is active and visible then completion will surround the
      region with the chosen tag's start and end tag.  However only the
      starting point is checked for validity. If something is wrong after
      insertion you will however immediately see it if you have validation
    - It can in some cases give assistance with attribute values.
    - Completion can be customized, see the menus XHTML - Completion:
      * You can use a menu popup style completion.
      * You can have alternatives grouped.
      * You can get a short help text shown for each alternative.
    - There does not have to be a ', C-c RET  Move
            between underlined href/src attributes
        C-c RET RET, Mouse-1 Follow link inside Emacs
            (if possible)
      It is even a little bit quicker when the links are in an active
      state (marked with the face `isearch'):
        , TAB Move
            between underlined href/src attributes
        RET, Mouse-1  Follow link inside Emacs (if possible)
      If the link is not into a file that you can edit (a mailto link
      for example) you will be prompted for an alternative action.
    * Creating links. To make it easier to create links to id/name
      attribute in different files there are two special
        C-c C-h c copy link to id/name (you must
            be in the tag to get the link)
        C-c C-h v paste this as an a-tag.
    Here are all key bindings in nxhtml-mode itself:
    key             binding
    ---             -------
    C-c		Prefix Command
    ESC		Prefix Command
    /		nxml-electric-slash
    C-c C-b		nxml-balanced-close-start-tag-block
    C-c C-d		nxml-dynamic-markup-word
    C-c C-f		rngalt-finish-element
    C-c C-h		Prefix Command
    C-c TAB		nxml-balanced-close-start-tag-inline
    C-c RET		nxml-split-element
    C-c C-n		rng-next-error
    C-c C-o		Prefix Command
    C-c C-p		Prefix Command
    C-c C-q		nxhtml-quote-html
    C-c C-s		Prefix Command
    C-c C-u		nxml-insert-named-char
    C-c C-v		rng-validate-mode
    C-c C-x		nxml-insert-xml-declaration
    C-c 	hs-mouse-toggle-hiding
    C-c @		Prefix Command
    C-c @ C-c	hs-toggle-hiding
    C-c @ C-h	hs-hide-block
    C-c @ C-l	hs-hide-level
    C-c @ C-s	hs-show-block
    C-c @ ESC	Prefix Command
    C-c @ C-M-h	hs-hide-all
    C-c @ C-M-s	hs-show-all
    Icomplete minor mode (no indicator):
    Toggle incremental minibuffer completion for this Emacs session.
    With a numeric argument, turn Icomplete mode on if ARG is positive,
    otherwise turn it off.
    Line-Number minor mode (no indicator):
    Toggle Line Number mode.
    With arg, turn Line Number mode on if arg is positive, otherwise
    turn it off.  When Line Number mode is enabled, the line number
    appears in the mode line.
    Line numbers do not appear for very large buffers and buffers
    with very long lines; see variables `line-number-display-limit'
    and `line-number-display-limit-width'.
    Menu-Bar minor mode (no indicator):
    Toggle display of a menu bar on each frame.
    This command applies to all frames that exist and frames to be
    created in the future.
    With a numeric argument, if the argument is positive,
    turn on menu bars; otherwise, turn off menu bars.
    Mlinks minor mode (indicator L):
    Recognizes certain parts of a buffer as hyperlinks.
    The hyperlinks are created in different ways for different major
    modes with the help of the functions in the list
    The hyperlinks can be hilighted when the point is over them.
    Use `mlinks-toggle-hilight' to toggle this feature for the
    current buffer.
    All keybindings in this mode are by default done under the prefi§x
      C-c RET
    which is supposed to be a kind of mnemonic for link (alluding to
    the RET key commonly used in web browser to follow a link).
    (Unfortunately this breaks the rules in info node `Key Binding
    Conventions'.) Below are the key bindings defined by this mode:
    key             binding
    ---             -------
    C-c		Prefix Command
    C-c RET		Prefix Command
    C-c RET RET	mlinks-goto
    C-c RET f	mlinks-goto-other-frame
    C-c RET h	mlinks-toggle-hilight
    C-c RET n	mlinks-next-saved-position
    C-c RET p	mlinks-prev-saved-position
    C-c RET w	mlinks-goto-other-window
    C-c RET 			mlinks-backward-link
    C-c RET 			mlinks-forward-link
    For some major modes `mlinks-backward-link' and
    `mlinks-forward-link' will take you to the previous/next link.
    By default the link moved to will be active, see
    Mouse-Wheel minor mode (no indicator):
    Toggle mouse wheel support.
    With prefix argument ARG, turn on if positive, otherwise off.
    Return non-nil if the new state is enabled.
    Nxhtml minor mode (no indicator):
    Minor mode to turn on some key and menu bindings.
    See `nxhtml-mode' for more information.
    Outline minor mode (indicator Outl):
    Toggle Outline minor mode.
    With arg, turn Outline minor mode on if arg is positive, off otherwise.
    See the command `outline-mode' for more information on this mode.
    Shell-Dirtrack minor mode (no indicator):
    Turn directory tracking on and off in a shell buffer.
    The `dirtrack' package provides an alternative implementation of this
    feature - see the function `dirtrack-mode'.
    Show-Paren minor mode (no indicator):
    Toggle Show Paren mode.
    With prefix ARG, turn Show Paren mode on if and only if ARG is positive.
    Returns the new status of Show Paren mode (non-nil means on).
    When Show Paren mode is enabled, any matching parenthesis is highlighted
    in `show-paren-style' after `show-paren-delay' seconds of Emacs idle time.
    Tabbar minor mode (no indicator):
    Toggle display of a tab bar in the header line.
    With prefix argument ARG, turn on if positive, otherwise off.
    Returns non-nil if the new state is enabled.
    Tooltip minor mode (no indicator):
    Toggle Tooltip mode.
    With ARG, turn Tooltip mode on if and only if ARG is positive.
    When this minor mode is enabled, Emacs displays help text
    in a pop-up window for buttons and menu items that you put the mouse on.
    (However, if `tooltip-use-echo-area' is non-nil, this and
    all pop-up help appears in the echo area.)
    When Tooltip mode is disabled, Emacs displays one line of
    the help text in the echo area, and does not make a pop-up window.
    Transient-Mark minor mode (no indicator):
    Toggle Transient Mark mode.
    With arg, turn Transient Mark mode on if arg is positive, off otherwise.
    In Transient Mark mode, when the mark is active, the region is highlighted.
    Changing the buffer "deactivates" the mark.
    So do certain other operations that set the mark
    but whose main purpose is something else--for example,
    incremental search, .
    You can also deactivate the mark by typing C-g or
    M-ESC ESC.
    Many commands change their behavior when Transient Mark mode is in effect
    and the mark is active, by acting on the region instead of their usual
    default part of the buffer's text.  Examples of such commands include
    M-;, M-x flush-lines, M-x keep-lines, M-%, C-M-%, M-x ispell, and C-_.
    Invoke C-h d and type "transient" or
    "mark.*active" at the prompt, to see the documentation of
    commands which are sensitive to the Transient Mark mode.
    Unify-8859-On-Encoding minor mode (no indicator):
    Set up translation-tables for unifying ISO 8859 characters on encoding.
    The ISO 8859 characters sets overlap, e.g. 8859-1 (Latin-1) and
    8859-15 (Latin-9) differ only in a few characters.  Emacs normally
    distinguishes equivalent characters from those ISO-8859 character sets
    which are built in to Emacs.  This behavior is essentially inherited
    from the European-originated international standards.  Treating them
    equivalently, by translating to and from a single representation is
    called `unification'.  (The `utf-8' coding system treats the
    characters of European scripts in a unified manner.)
    In this mode, on encoding -- i.e. output operations -- non-ASCII
    characters from the built-in ISO 8859 and `mule-unicode-0100-24ff'
    charsets are handled automatically by the coding system used if it can
    represent them.  Thus, say, an e-acute from the Latin-1 charset (the
    unified representation) in a buffer saved as Latin-9 will be encoded
    directly to a byte value 233.  By default, in contrast, you would be
    prompted for a general coding system to use for saving the file, which
    can cope with separate Latin-1 and Latin-9 representations of e-acute.
    Also sets hooks that arrange `translation-table-for-input' to be set
    up locally.  This will often allow input generated by Quail input
    methods to conform with what the buffer's file coding system can
    encode.  Thus you could use a Latin-2 input method to search for
    e-acute in a Latin-1 buffer.
    See also command `unify-8859-on-decoding-mode'.
    Utf-Translate-Cjk minor mode (no indicator):
    Toggle whether UTF based coding systems de/encode CJK characters.
    If ARG is an integer, enable if ARG is positive and disable if
    zero or negative.  This is a minor mode.
    Enabling this allows the coding systems mule-utf-8,
    mule-utf-16le and mule-utf-16be to encode characters in the charsets
    `korean-ksc5601', `chinese-gb2312', `chinese-big5-1',
    `chinese-big5-2', `japanese-jisx0208' and `japanese-jisx0212', and to
    decode the corresponding unicodes into such characters.
    Where the charsets overlap, the one preferred for decoding is chosen
    according to the language environment in effect when this option is
    turned on: ksc5601 for Korean, gb2312 for Chinese-GB, big5 for
    Chinese-Big5 and jisx for other environments.
    This mode is on by default.  If you are not interested in CJK
    characters and want to avoid some overhead on encoding/decoding
    by the above coding systems, you can customize the user option
    `utf-translate-cjk-mode' to nil.
    Yas/Minor minor mode (indicator yas):
    Toggle YASnippet mode.
    With no argument, this command toggles the mode.
    positive prefix argument turns on the mode.
    Negative prefix argument turns off the mode.
    When YASnippet mode is enabled, the TAB key
    expands snippets of code depending on the mode.
    You can customize the key through `yas/trigger-key'.

    By transtone on Jul 9, 2008

  14. @transtone,
    呵呵,好多内容。看样子 nxhtml-mode 也是一个 minor-mode ,好像它占优先的样子。你在设置了 local-set-key 的 hook 之后重新打开那个文件,再 C-h k 看是绑定到 yas/expand 还是 indent-for-tab-command 啊?

    By pluskid on Jul 9, 2008

  15. 我的上上个回复正是添加了local-set-key 的 hook 之后 C-h k 时的信息。

    By transtone on Jul 10, 2008

  16. @transtone,
    这样的,看那里开了好多的 minor-mode ,看样子好像 键被某个 mode 抢先了,我好像没有在 nxhtml-mode 的代码里找到相关的东西。你试试手工 M-x yas/expand ,如果能展开的话就是按键的问题,可以尝试这样:

    (add-hook 'hxhtml-mode-hook
    	  '(lambda ()
    	     (make-variable-buffer-local 'yas/trigger-key)
    	     (setq yas/trigger-key [tab])))


    By pluskid on Jul 10, 2008

Post a Comment