A few years ago I modified version 1.8.1 of Jason Blevins's markdown-mode for Emacs so that when showing inline links the URL is hidden, and so that you can follow the link simply by hitting Enter. If you want to see the URL you can still see it by, say, removing the final ). It's based on linkd, though I'm told that org-mode's org-activate-bracket-links achieves something similar.

I'm sure there are potential areas for improvement in my code for a number of reasons:

  1. I'm still learning Elisp
  2. It seems like I should have been able to accomplish the task with less code
  3. When I try to port the code to the newest version of markdown-mode (version 2.0; available here for the moment), it breaks in a confusing way
  4. My code doesn't play nicely with adaptive-wrap; I don't get a hanging indent for lines that start in the middle of a URL

I've posted my code at http://pastebin.com/AqQSqeWM, but the change consists only of changing

   (cons markdown-regex-link-inline
         '((1 markdown-link-face t)
           (2 markdown-url-face t)))


   (cons markdown-regex-link-inline
         '((0 (let
                  ((link-beg (match-beginning 1))
                   (link-end (match-end 1))
                   (url-beg (match-beginning 2))
                   (url-end (match-end 2)))
                (markdown-linkd-render-link link-beg link-end url-beg url-end markdown-link-face)

and then tack on this code somewhere:

(defun markdown-linkd-follow-at-point ()
  "Follow the link at point."
  (loop for ov in (overlays-at (point)) do
        (let ((url (overlay-get ov 'markdown-linkd-url)))
          (when url
            (browse-url url)))))

(defun markdown-linkd-follow-mouse (event)
  "Follow the clicked link."
  (interactive "e")
  (when event
    (select-window (posn-window (event-start event)))
    (set-buffer (window-buffer (posn-window (event-start event))))
    (goto-char (posn-point (event-start event)))

(defvar markdown-linkd-overlay-map nil "Keymap for Linkd overlays.")
(unless markdown-linkd-overlay-map
  (setq markdown-linkd-overlay-map (make-sparse-keymap))
  (define-key markdown-linkd-overlay-map (kbd "RET")
  (define-key markdown-linkd-overlay-map [mouse-2] 'markdown-linkd-follow-mouse))

(defun markdown-linkd-overlay-at-p (loc)
  (loop for ov in (overlays-at loc)
        thereis (overlay-get ov 'markdown-linkd-url)))

(defun markdown-linkd-render-link (link-beg link-end url-beg url-end display-face)
  ;; It's not enough to mark links with a text property because text properties get copied and overlays do not
  (unless (markdown-linkd-overlay-at-p link-beg)
    (let ((url (buffer-substring-no-properties (1+ url-beg) (1- url-end)))
          (display-text (concat 
                         (buffer-substring-no-properties link-beg link-end)
      (markdown-linkd-overlay link-beg url-end url display-text display-face))))

(defun markdown-linkd-overlay (beg end url display-text display-face)
  "Apply Linkd overlay to link text"
  (let ((overlay (make-overlay beg end))
         (list (lambda (ov foo beg end &rest ignore)
                 (delete-overlay ov)
     ;; Could maybe use invisible text rather than display-text, but this
     ;; way makes it easy to also get a live link with a single overlay
     overlay 'display (propertize display-text
                                  'face display-face
                                  'keymap markdown-linkd-overlay-map)) ; add speed-navigation keys
    (overlay-put overlay 'mouse-face 'highlight)
    (overlay-put overlay 'keymap markdown-linkd-overlay-map) ; add speed-navigation keys
    (overlay-put overlay 'evaporate t)
    (overlay-put overlay 'markdown-linkd-url url)
    (overlay-put overlay 'modification-hooks overlay-modification-code)
    (overlay-put overlay 'insert-in-front-hooks overlay-modification-code)
    (overlay-put overlay 'insert-behind-hooks overlay-modification-code)))

;; Sometimes reverting a file confuses my markdown-linkd stuff. This is
;; a heavy-handed attempt to solve the problem
(add-hook 'after-revert-hook 'remove-overlays)

Your Answer

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

Browse other questions tagged or ask your own question.