17

I would like to use the SE flavor of markdown in my emacs. The default Markdown mode has some features (backticks and indentation mark code, # makes a header and > also changes the font) but I would also like to have:

  • * to make a list item, including indentation.
  • [foo](http://example.com) to show up as foo and open a browser to http://example.com when clicked.

Ideally, I would like this to be shown in my emacs as rendered Markdown. For example, if I were to write:

## Header

* item 1
* item 2

         while true; do echo foo; done

End of list and more code

    while true; do echo bar; done

 See [here](http://example.com) for details

I'd like it to be rendered like this in emacs itself:


Header

  • item 1
  • item 2

    while true; do echo foo; done
    

End of list and more code

while true; do echo bar; done

See here for details


Can this be achieved and, if so, how?

  • About the code block being rendered: doesn't Markdown mode highlight code blocks for you already? What were you looking for there? – Malabarba Oct 6 '14 at 21:27
  • Also, do you want this to be editable, like a WYSIWYG Markdown editor? Or is it enough to display the "compiled" output in a separate buffer? The latter is rather simple, the former is a coding behemoth. – Malabarba Oct 6 '14 at 21:32
  • @Malabarba, yes, the code is fine. What I would like is i) auto indented lists ii) url handling. Either through xdg-open or even just simply displaying the target address when clicked on but the link text when not: "Click here" to become Click [here](http://example.com) when clicked. Just a quick way to seamlessly include URLs in my text documents. – terdon Oct 6 '14 at 21:55
  • OK, then both of these can be achieved with font-lock-add-keyword. I'll try to write something up tomorrow, if nobody beats me to it. – Malabarba Oct 6 '14 at 22:03
19

**EDIT: ** 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.


Configuration

There are two approaches you can take.

  1. You can write a command that compiles the markdown code (using a shell command) and displays the html in a buffer.
  2. 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 display it).

(defvar endless/bullet-appearance
  (propertize (if (char-displayable-p ?•) "  •" "  *")
              'face 'markdown-list-face)
  "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.

(require 'rx)
(defvar endless/markdown-link-regexp
    "\\[\\(?1:[^]]+\\)]\\(?:(\\(?2:[^)]+\\))\\|\\[\\(?3:[^]]+\\)]\\)"
  "Regexp matching a markdown link.")

(font-lock-add-keywords
 'markdown-mode
 '(("^ *\\(\\*\\|\\+\\|-\\|\\) "
    1 `(face nil display ,endless/bullet-appearance) prepend)
   (endless/markdown-link-regexp
    1 '(face nil display "") prepend))
 'append)

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."
  (interactive)
  (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)
                        (looking-at endless/markdown-link-regexp)))))
      (let ((data (endless/ask-for-link
                   (match-string-no-properties 1) 
                   (or (match-string-no-properties 2)
                       (match-string-no-properties 3)))))
        (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.

(custom-set-faces
 '(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")))))

Results

Here’s what you’ll get after the first 2 set of configurations:
enter image description here

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.
enter image description here

  • Wow! That's pretty near perfect, thanks. This answers everything I asked for, but for extra brownie points, is there a way to make the link more interactive? I mean, an easy way to extract the URL. Would it be possible to toggle between [foo] and [foo](http://bar.com) by clicking? I'm not too bothered on the details but would like a way of easily displaying the URL if desired. At the moment, I have to delete one of the brackets for it to appear. I can live with that but I'd be interested in a better way. – terdon Oct 7 '14 at 12:45
  • @terdon Done!.. – Malabarba Oct 7 '14 at 14:01
  • I am going to combine this with Edit with Emacs, and then I will take over the Tri-State Area! – nispio Oct 7 '14 at 14:08
  • @Malabarba there seems to be an error there. I get "Unknown rx form group-n'". Output of --debug-init` here. Any ideas? – terdon Oct 7 '14 at 14:28
  • @terdon It's possible group-n is only defined in 24.4, I'll try to check. You can try replacing each of the group-n X with just group. That might still work. – Malabarba Oct 7 '14 at 15:31
5

A good place to start would be markdown-mode.el which can be downloaded from here.

This mode does not offer org-mode style beautification, but it does offer syntax highlighting and a bevy of customize options.

In order to get this style beautification, someone would need to write an extension to markdown-mode.el implementing font-faces.

  • Most of org-mode.el's faces are defined in org-faces.el.

  • Additionally you will want to take a look at how org-mode visually replaces text with characters. That code is in org-entities.el. This is the code that replaces the latex \pm with ±.

  • Thanks, I'm using markdown mode at the moment, as I mention in my answer. I would like to know how to implement the features that are missing and also how to have emacs display them as rendered. Alternatively, I'd like to know that it's impossible to display them rendered if that's the case. – terdon Oct 6 '14 at 19:16
  • It is possible to do so, org-mode does syntax beautification like that. Give me a few moments to find the code. I have done similar coding for another major-mode. I did not realize that you already knew about markdown.el. – nixeagle Oct 6 '14 at 19:19
  • I have edited the answer to provide a way to start doing what you want. When I get home, I might be able to bang up some code that does exactly what you want. As it is, org-mode modifies titles to hide the * denoting levels and changes the size of the title based on where it is in the document. It also is able to pretty-format links. – nixeagle Oct 6 '14 at 19:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.