Skip to content

Commit

Permalink
Font lock for HTML tags and attributes
Browse files Browse the repository at this point in the history
Closes GH-249
  • Loading branch information
jrblevin committed Nov 13, 2017
1 parent d4de627 commit e3e7069
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 0 deletions.
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
Alexis Gallagher for a patch. ([GH-272][], [GH-274][])
- Added pipe table editing features. Thanks to Dmitry Safronov
for a patch. ([GH-171][], [GH-266][])
- Font lock for HTML tags and attributes, with new faces
`markdown-html-tag-name-face`,
`markdown-html-tag-delimiter-face`,
`markdown-html-attr-name-face`, and
`markdown-html-attr-value-face`. ([GH-249][])
- Font lock for HTML entities, with a new face
`markdown-html-entity-face`.

Expand Down Expand Up @@ -70,6 +75,7 @@
[gh-238]: https://github.com/jrblevin/markdown-mode/issues/238
[gh-246]: https://github.com/jrblevin/markdown-mode/issues/246
[gh-248]: https://github.com/jrblevin/markdown-mode/issues/248
[gh-249]: https://github.com/jrblevin/markdown-mode/issues/249
[gh-251]: https://github.com/jrblevin/markdown-mode/issues/251
[gh-252]: https://github.com/jrblevin/markdown-mode/pull/252
[gh-254]: https://github.com/jrblevin/markdown-mode/issues/254
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,9 @@ provides an interface to all of the possible customizations:
interactively later using <kbd>C-c C-x C-e</kbd>
(`markdown-toggle-math`).

* `markdown-enable-html` - font lock for HTML tags and attributes
(default: `t`).

* `markdown-css-paths` - CSS files to link to in XHTML output
(default: `nil`).

Expand Down
70 changes: 70 additions & 0 deletions markdown-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,9 @@
;; interactively later using `C-c C-x C-e`
;; (`markdown-toggle-math').
;;
;; * `markdown-enable-html' - font lock for HTML tags and attributes
;; (default: `t').
;;
;; * `markdown-css-paths' - CSS files to link to in XHTML output
;; (default: `nil`).
;;
Expand Down Expand Up @@ -1341,6 +1344,13 @@ Math support can be enabled, disabled, or toggled later using
:safe 'booleanp)
(make-variable-buffer-local 'markdown-enable-math)

(defcustom markdown-enable-html t
"Enable font-lock support for HTML tags and attributes."
:group 'markdown
:type 'boolean
:safe 'booleanp
:package-version '(markdown-mode . "2.4"))

(defcustom markdown-css-paths nil
"URL of CSS file to link to in the output XHTML."
:group 'markdown
Expand Down Expand Up @@ -1886,6 +1896,22 @@ Group 2 matches the opening square bracket.
Group 3 matches the footnote text, without the surrounding markup.
Group 4 matches the closing square bracket.")

(defconst markdown-regex-html-attr
"\\(\\<[[:alpha:]:-]+\\>\\)\\(\\s-*\\(=\\)\\s-*\\(\".*?\"\\|'.*?'\\|[^'\">[:space:]]+\\)?\\)?"
"Regular expression for matching HTML attributes and values.
Group 1 matches the attribute name.
Group 2 matches the following whitespace, equals sign, and value, if any.
Group 3 matches the equals sign, if any.
Group 4 matches single-, double-, or un-quoted attribute values.")

(defconst markdown-regex-html-tag
(concat "\\(</?\\)\\(\\w+\\)\\(\\(\\s-+" markdown-regex-html-attr
"\\)+\\s-*\\|\\s-*\\)\\(/?>\\)")
"Regular expression for matching HTML tags.
Groups 1 and 9 match the beginning and ending angle brackets and slashes.
Group 2 matches the tag name.
Group 3 matches all attributes and whitespace following the tag name.")

(defconst markdown-regex-html-entity
"\\(&#?[[:alnum:]]+;\\)"
"Regular expression for matching HTML entities.")
Expand Down Expand Up @@ -2767,6 +2793,26 @@ For example, this applies to plain angle bracket URLs:
"Face for horizontal rules."
:group 'markdown-faces)

(defface markdown-html-tag-name-face
'((t (:inherit font-lock-type-face)))
"Face for HTML tag names."
:group 'markdown-faces)

(defface markdown-html-tag-delimiter-face
'((t (:inherit markdown-markup-face)))
"Face for HTML tag delimiters."
:group 'markdown-faces)

(defface markdown-html-attr-name-face
'((t (:inherit font-lock-variable-name-face)))
"Face for HTML attribute names."
:group 'markdown-faces)

(defface markdown-html-attr-value-face
'((t (:inherit font-lock-string-face)))
"Face for HTML attribute values."
:group 'markdown-faces)

(defface markdown-html-entity-face
'((t (:inherit font-lock-variable-name-face)))
"Face for HTML entities."
Expand Down Expand Up @@ -2890,6 +2936,20 @@ Depending on your font, some reasonable choices are:
(3 markdown-markup-properties)))
(markdown-fontify-angle-uris)
(,markdown-regex-email . 'markdown-plain-url-face)
(markdown-match-html-tag . ((1 'markdown-html-tag-delimiter-face t)
(2 'markdown-html-tag-name-face t)
(3 'markdown-html-tag-delimiter-face t)
;; Anchored matcher for HTML tag attributes
(,markdown-regex-html-attr
;; Before searching, move past tag
;; name; set limit at tag close.
(progn
(goto-char (match-end 2)) (match-end 3))
nil
. ((1 'markdown-html-attr-name-face)
(3 'markdown-html-tag-delimiter-face nil t)
(4 'markdown-html-attr-value-face nil t)))))
(,markdown-regex-html-entity . 'markdown-html-entity-face)
(markdown-fontify-list-items)
(,markdown-regex-footnote . ((0 markdown-inline-footnote-properties)
(1 markdown-markup-properties) ; [^
Expand Down Expand Up @@ -4158,6 +4218,16 @@ Group 7: closing filename delimiter"
(setq valid (markdown-match-includes last)))))
valid)))

(defun markdown-match-html-tag (last)
"Match HTML tags from point to LAST."
(when (and markdown-enable-html
(markdown-match-inline-generic markdown-regex-html-tag last t))
(set-match-data (list (match-beginning 0) (match-end 0)
(match-beginning 1) (match-end 1)
(match-beginning 2) (match-end 2)
(match-beginning 9) (match-end 9)))
t))


;;; Markdown Font Fontification Functions =====================================

Expand Down
70 changes: 70 additions & 0 deletions tests/markdown-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -3137,6 +3137,76 @@ across blocks]"
(markdown-range-property-any
(point-min) (point-max) 'face '(markdown-html-entity-face)))))

(ert-deftest test-markdown-font-lock/html-tags-in-syntax-file ()
"Test matching HTML tags in syntax.text."
(markdown-test-file "syntax.text"
;; <ul id="ProjectSubmenu">
(markdown-test-range-has-face 36 36 'markdown-html-tag-delimiter-face)
(markdown-test-range-has-face 37 38 'markdown-html-tag-name-face)
(markdown-test-range-has-face 40 41 'markdown-html-attr-name-face)
(markdown-test-range-has-face 42 42 'markdown-html-tag-delimiter-face)
(markdown-test-range-has-face 43 58 'markdown-html-attr-value-face)
(markdown-test-range-has-face 59 59 'markdown-html-tag-delimiter-face)
;; <li>
(markdown-test-range-has-face 65 65 'markdown-html-tag-delimiter-face)
(markdown-test-range-has-face 66 67 'markdown-html-tag-name-face)
(markdown-test-range-has-face 68 68 'markdown-html-tag-delimiter-face)
;; <a href="/projects/markdown/" title="Markdown Project Page">
(markdown-test-range-has-face 69 69 'markdown-html-tag-delimiter-face)
(markdown-test-range-has-face 70 70 'markdown-html-tag-name-face)
(markdown-test-range-has-face 72 75 'markdown-html-attr-name-face)
(markdown-test-range-has-face 76 76 'markdown-html-tag-delimiter-face)
(markdown-test-range-has-face 77 97 'markdown-html-attr-value-face)
(markdown-test-range-has-face 99 103 'markdown-html-attr-name-face)
(markdown-test-range-has-face 104 104 'markdown-html-tag-delimiter-face)
(markdown-test-range-has-face 105 127 'markdown-html-attr-value-face)
(markdown-test-range-has-face 128 128 'markdown-html-tag-delimiter-face)))

(ert-deftest test-markdown-font-lock/html-tag-in-gfm-code-block ()
"Test that HTML tags are not matched inside GFM code blocks."
(markdown-test-string "```\n<ul id=\"ProjectSubmenu\">\n```"
(should-not
(markdown-range-property-any
(point-min) (point-max) 'face
'(markdown-html-tag-name-face
markdown-html-tag-delimiter-face
markdown-html-attr-name-face
markdown-html-attr-value-face)))))

(ert-deftest test-markdown-font-lock/html-tag-in-code-block ()
"Test that HTML tags are not matched inside code blocks."
(markdown-test-string " <ul id=\"ProjectSubmenu\">"
(should-not
(markdown-range-property-any
(point-min) (point-max) 'face
'(markdown-html-tag-name-face
markdown-html-tag-delimiter-face
markdown-html-attr-name-face
markdown-html-attr-value-face)))))

(ert-deftest test-markdown-font-lock/html-tag-in-inline-code ()
"Test that HTML tags are not matched inside inline code spans."
(markdown-test-string "`<ul id=\"ProjectSubmenu\">`"
(should-not
(markdown-range-property-any
(point-min) (point-max) 'face
'(markdown-html-tag-name-face
markdown-html-tag-delimiter-face
markdown-html-attr-name-face
markdown-html-attr-value-face)))))

(ert-deftest test-markdown-font-lock/html-disabled ()
"Test disabling font-lock for HTML tags"
(let ((markdown-enable-html nil))
(markdown-test-file "syntax.text"
(should-not
(markdown-range-property-any
(point-min) (point-max) 'face
'(markdown-html-tag-name-face
markdown-html-tag-delimiter-face
markdown-html-attr-name-face
markdown-html-attr-value-face))))))

;;; Markdown Parsing Functions:

(ert-deftest test-markdown-parsing/extend-region-function ()
Expand Down

0 comments on commit e3e7069

Please sign in to comment.