Since this writing, it seems that part of the features have been directly implemented in markdown-mode. Check out this comment, and the links therein.
There are two approaches you can take.
- You can write a command that compiles the markdown code (using a
shell command) and displays the html in a buffer.
- You can make some customizations a-la org-mode to make the buffer look like rendered markdown.
I explain here how to implement number 2. Simply copy all of the code
below to you init file.
Add the font-lock rules
This variable controls how you want lists to look. It adds some space
to indent the list, and uses a pretty bullet-point (if your font can
(propertize (if (char-displayable-p ?•) " •" " *")
"String to be displayed as the bullet of markdown list items.")
This is the command that actually adds the rules. There is one for lists and one for links.
"Regexp matching a markdown link.")
'(("^ *\\(\\*\\|\\+\\|-\\|\\) "
1 `(face nil display ,endless/bullet-appearance) prepend)
1 '(face nil display "") prepend))
Make the link editable
Because we’re using the
display property to hide part of the link,
we need to tell font-lock that it should erase that property whenever
you delete part of the link (that way we can still edit it).
(add-hook 'markdown-mode-hook #'endless/markdown-font-lock)
(defun endless/markdown-font-lock ()
"Configure aggressive font-locking of `markdown-mode'."
(define-key markdown-mode-map "\C-c\C-l" #'endless/markdown-insert-link)
(add-to-list (make-local-variable 'font-lock-extra-managed-props) 'display))
We can also define a command to edit it easily, bound to
C-c C-l, like in org-mode.
(defun endless/markdown-insert-link ()
"Insert or edit link at point."
(if (or (looking-at endless/markdown-link-regexp)
(and (ignore-errors (backward-up-list) t)
(or (looking-at endless/markdown-link-regexp)
(and (forward-sexp -1)
(let ((data (endless/ask-for-link
(or (match-string-no-properties 2)
(if (match-string-no-properties 2)
(replace-match (cdr data) :fixedcase :literal nil 2)
(replace-match (cdr data) :fixedcase :literal nil 3))
(replace-match (car data) :fixedcase :literal nil 1))
(let ((data (endless/ask-for-link)))
(insert "[" (car data) "](" (cdr data) ")"))))
(defun endless/ask-for-link (&optional name link)
(cons (read-string "Text of the link: " name)
(read-string "URL of the link: " link)))
(Optional) Configure some faces
That should be enough for the points you requested. If you want your
buffer to look even more like SE markdown, call
M-x customize-group RET markdown-faces
and change what you see fit. I did some configuring myself, and here’s
what I got.
'(markdown-header-face-1 ((t (:inherit markdown-header-face :height 2.0))))
'(markdown-header-face-2 ((t (:inherit markdown-header-face :height 1.7))))
'(markdown-header-face-3 ((t (:inherit markdown-header-face :height 1.4))))
'(markdown-header-face-4 ((t (:inherit markdown-header-face :height 1.1))))
'(markdown-inline-code-face ((t (:inherit font-lock-constant-face :background "gainsboro"))))
'(markdown-link-face ((t (:inherit link))))
'(markdown-pre-face ((t (:inherit font-lock-constant-face :background "gainsboro")))))
Here’s what you’ll get after the first 2 set of configurations:
Here’s what you’ll get after configuring faces as well. It’s arguable
whether this looks better, I’ll personally stick with the one above.