Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: e660ed02c7
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 266 lines (213 sloc) 7.384 kb

org-link-minor-mode

Header

;;; org-link-minor-mode.el -- Enable org-mode links in non-org modes
;;
;; Copyright (C) 2012
;; Author: Sean O'Halpin <sean dot ohalpin at gmail dot com>
;;
;; Enables org-mode links of the form:
;;
;;   http://www.bbc.co.uk
;;   man:emacs
;;   <http://www.bbc.co.uk>
;;   [[http://www.bbc.co.uk][BBC]]
;;   [[org-link-minor-mode]]
;;   [2012-08-18]
;;   <2012-08-18>
;;
;; Note that =org-toggle-link-display= will also work when this mode
;; is enabled.
;;

Require org-mode

As we rely on many org-mode functions, to avoid warnings, we load org-mode:

(require 'org)

Using the define-minor-mode macro

The simplest way to define a new minor mode is to use the =define-minor-mode= macro:

(define-minor-mode org-link-minor-mode
  "Toggle display of org-mode style bracket links in non-org-mode buffers."
  :lighter " org-link"

  <<body>>
  )

The :lighter keyword parameter defines what appears in the mode line.

The body

We start the body by setting up the font lock keywords, using org-mode’s org-activate-bracket-links, etc. to do the heavy lifting. We then branch depending on whether we’re entering or exiting the mode:

(let ((org-link-minor-mode-keywords
       (list
        '(org-activate-angle-links (0 'org-link t))
        '(org-activate-plain-links)
        '(org-activate-bracket-links (0 'org-link t))
        '(org-activate-dates (0 'org-date t))
        ))
      )
  (if org-link-minor-mode
      <<enter-minor-mode>>
    <<exit-minor-mode>>
    )
  )

Entering the minor mode

If we’re already in org-mode, display a message and switch org-link-minor-mode off. We need to do it this way as by this point we’ve already entered the minor mode (org-link-minor-mode == t):

(if (derived-mode-p 'org-mode)
    (progn
      (message "org-mode doesn't need org-link-minor-mode")
      (org-link-minor-mode -1)
      )
  <<enter-minor-mode-body>>
  )

Turning on org-link highlighting

Add the font-lock specification:

(font-lock-add-keywords nil org-link-minor-mode-keywords t)

Enable return to follow link (and tab to next link, backtab to previous):

(kill-local-variable 'org-mouse-map)
(org-set-local 'org-mouse-map
               (let ((map (make-sparse-keymap)))
                 (define-key map [return] 'org-open-at-point)
                 (define-key map [tab] 'org-next-link)
                 (define-key map [backtab] 'org-previous-link)
                 (define-key map [mouse-2] 'org-open-at-point)
                 (define-key map [follow-link] 'mouse-face)
                 map)
               )

Reusing org-mouse-map like this is a hack. This keymap is set as a text property of links in org-activate-bracket-links, etc. so it’s simpler to co-opt it than to replace those functions.

Enable org-toggle-link-display for this buffer only by making org-descriptive-links buffer local:

(org-set-local 'org-descriptive-links org-descriptive-links)
(if org-descriptive-links (add-to-invisibility-spec '(org-link)))

This is the magic that makes the link body appear if you backspace into it (or use replace to make it no longer a link):

(org-set-local 'font-lock-unfontify-region-function
               'org-link-minor-mode-unfontify-region)

The documentation for =font-lock-unfontify-region-function= is a bit sparse but reading org-unfontify-region at least shows you what it should do.

Finally, we refontify the buffer using org’s own method:

(org-restart-font-lock)

Exiting the minor mode

Again, we don’t run this code if we’re already in org-mode:

(unless (derived-mode-p 'org-mode)
  <<exit-minor-mode-body>>
  )

Exit minor mode body

Remove all org-link properties:

(font-lock-remove-keywords nil org-link-minor-mode-keywords)

Restore existing font lock highlighting

(org-restart-font-lock)
(remove-from-invisibility-spec '(org-link))
(kill-local-variable 'org-descriptive-links)
(kill-local-variable 'org-mouse-map)
(kill-local-variable 'font-lock-unfontify-region-function)

Remove text properties

org-unfontify-region does not remove the help-echo and rear-nonsticky properties, so I’ve copied the function and added those in.

Actually, this looks like a bug in org-unfontify-region.

(Note: should I be removing the fontified property too? It doesn’t look like other modes do this.)

(defun org-link-minor-mode-unfontify-region (beg end &optional maybe_loudly)
  "Remove fontification and activation overlays from links."
  (font-lock-default-unfontify-region beg end)
  (let* ((buffer-undo-list t)
         (inhibit-read-only t) (inhibit-point-motion-hooks t)
         (inhibit-modification-hooks t)
         deactivate-mark buffer-file-name buffer-file-truename)
    (org-decompose-region beg end)
    (remove-text-properties beg end
                            '(mouse-face t keymap t org-linked-text t
                                         invisible t intangible t
                                         help-echo t rear-nonsticky t
                                         org-no-flyspell t org-emphasis t))
    (org-remove-font-lock-display-properties beg end)))

Provide

Finally, we add the provide feature clause so that we can later (require org-link-minor-mode).

(provide 'org-link-minor-mode)

Complete source

Here is the complete source:

<<header-comments>>

<<requires>>

<<org-link-minor-mode-unfontify-region>>

<<define-minor-mode>>

<<provide>>
Something went wrong with that request. Please try again.