By using polymode for Emacs, you can achieve multi-major modes in a single buffer. I made use of this great library to get LiveView syntax highlighting when using the ~L sigil.

;; Assumes web-mode and elixir-mode are already set up
(use-package polymode
  :mode ("\.ex$" . poly-elixir-web-mode)
  (define-hostmode poly-elixir-hostmode :mode 'elixir-mode)
  (define-innermode poly-liveview-expr-elixir-innermode
    :mode 'web-mode
    :head-matcher (rx line-start (* space) "~L" (= 3 (char "\"'")) line-end)
    :tail-matcher (rx line-start (* space) (= 3 (char "\"'")) line-end)
    :head-mode 'host
    :tail-mode 'host
    :allow-nested nil
    :keep-in-mode 'host
    :fallback-mode 'host)
  (define-polymode poly-elixir-web-mode
    :hostmode 'poly-elixir-hostmode
    :innermodes '(poly-liveview-expr-elixir-innermode))
(setq web-mode-engines-alist '(("elixir" . "\\.ex\\'")))

This gives you syntax highlighting via web-mode which I contributed better syntax highlighting for Elixir this week.

If you do not have the latest MELPA version of web-mode the code above will still work, but you will not have the extra syntax highlighting for variables and keywords.

Highlighting enabled (using with Doom Emacs)

I need to make some additional improvements to the code in order to get indent and smartparens behavior, but it's a big improvement from before.


Missing HTML highlighting

  1. Ensure you are running 0.2.2 of polymode. Recent commits seem to have broken something. I have opened an issue with polymode to figure out the cause.
    If you are using straight.el, you can pin to commit sha 44265e3 till things are fixed in MELPA.
    If you have access to MELPA Stable, 0.2.2 should be the current version hosted there.
  2. Check that the syntax is correct. If you have any typos, web-mode will not load. If that is correct, play with the :mode line to make sure poly-elixir-web-mode is loading in the correct order.
  3. You can try :hook (elixir-mode . poly-elixir-web-mode) and see if you get different results.