{ Tue, 03. Dec 2013 }

Inserting Blank Lines between HTML Tags in Emacs

I code HTML in Emacs, and Emmet makes it a breeze. Although, there was one thing that bugged me. When I expand div, Emmet gives me

1
<div>|</div>

with the cursor stuck right there in the middle. I (and I think I’m not alone with that) would prefer

1
2
3
<div>
    |
</div>

Getting from the one thing to the other is a mess of inserting newlines and moving the point, and indenting.

Don’t Fear, elisp is here!

Until now. This being Emacs, there’s a way around this. With the following snippet in my config, everything gets expanded and indented properly when I hit RET between an opening and closing tag.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
;; redefine newline
(defun sgml-before-is-opening-tag ()
  "Check if the tag preceding point is an opening tag."
  (save-excursion
    (let ((pre-tag-position (search-backward "<")))
      (if (string= (string (char-after (+ pre-tag-position 1))) "/")
          nil
        t))))

(defun sgml-after-is-closing-tag ()
  "Check if the tag following point is a closing tag."
  (save-excursion
    (let ((post-tag-position (search-forward "<")))
      (if (string= (string (char-after post-tag-position)) "/")
          t
        nil))))

(defun sgml-is-between-tags ()
  "Check if point is immediately between two tags (>|<)"
  (let ((before (string (preceding-char)))
        (after  (string (following-char))))
    (if (and
         (string= before ">")
         (string= after "<"))
        t
      nil)))

(defun sgml-newline ()
  "Insert two newlines when point is between opening and closing tags (>|</)"
  (interactive)
  (if (and
       (sgml-is-between-tags)
       (sgml-before-is-opening-tag)
       (sgml-after-is-closing-tag))
      (progn
        (newline-and-indent)
        (newline-and-indent)
        (forward-line -1)
        (indent-according-to-mode))
    (newline-and-indent)))

;; keybindings
(eval-after-load "sgml-mode"
  '(progn
     (define-key sgml-mode-map (kbd "RET") 'sgml-newline)))