The header has the following structure:
;;; <<title-line>>
;;
;; <<copyright>>
;;
;; <<package-info>>
;;
;; <<gnu-std-header>>
;;
;;; Commentary:
;;
;; <<commentary>>
;;
;;; Code:
The title line is the first line in the file and shows the name of the file and a short description. It also turns on {{{var(lexical-binding)}}}.
org-link-minor-mode.el --- Enable org-mode links in non-org modes -*- lexical-binding: t; -*-
Copyright (C) 2012-2020
Sean O'Halpin <sean.ohalpin@gmail.com>
20120825
(format-time-string "%Y%m%d")
0.0.3
(format-time-string "%Y%m%d.%H%M")
Specify the package metadata and that it requires at least Org 8 and
Emacs 24.3 (for lexical-binding
and setq-local
):
Author: <<email>>
Maintainer: <<email>>
Created: <<created>>
Modified: <<modified()>>
Version: <<version>>
Package-Requires: ((emacs "24.3"))
Package-Version: <<package-version()>>
Keywords: hypermedia
Url: https://github.com/seanohalpin/org-link-minor-mode
Changes for org v9: Stefan-W. Hahn <stefan dot hahn at s-hahn dot de>
All files submitted to ELPA should contain the standard GNU GPL 3 comment:
This file is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
A brief explanation of the package:
Enables org-mode links of the form:
http://www.bbc.co.uk
man:emacs
info: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.
We require org-element
to avoid the error
Error during redisplay: (jit-lock-function 1) signaled (void-variable org-element-paragraph-separate)
(require 'org-element)
;; Following declarations are necessary to make the byte compiler happy.
;; For org v8 compatibility (if used with org v9)
(declare-function org-activate-plain-links "org" (limit))
(declare-function org-activate-angle-links "org" (limit))
(declare-function org-activate-bracket-links "org" (limit))
(declare-function org-decompose-region "org-compat" (beg end))
;; For org v9 compatibility (if used with org v8)
(declare-function org-activate-links "org" (limit))
(declare-function org-activate-dates "org" (limit))
The simplest way to define a new minor mode is to use the {{{fn(define-minor-mode)}}} macro:
;;;###autoload
(define-minor-mode org-link-minor-mode
"Toggle display of org-mode style links in non-org-mode buffers."
:lighter " org-link"
:keymap org-link-minor-mode-map
<<body>>)
The {{{kw(autoload)}}} magic comment is used by emacs at build time to add the {{{fn(org-link-minor-mode)}}} function to {{{file(loaddefs.el)}}}.
The {{{kw(:lighter)}}} keyword parameter defines what appears in the mode line.
(let ((lk org-highlight-links)
org-link-minor-mode-keywords)
<<set-up-font-lock-keywords>>
<<enter-exit-mode>>)
We start the body by setting up the font lock keywords in the variable {{{var(org-link-minor-mode-keywords)}}}, using org-mode’s own {{{fn(org-activate-xxx)}}} functions to do the heavy lifting.
Note: we do this before entering the mode so the definition of {{{var(org-link-minor-mode-keywords)}}} is available for when we want to leave the mode.
(if (fboundp 'org-activate-links)
;; from Org v9.2
(setq org-link-minor-mode-keywords
(list
'(org-activate-links)
(when (memq 'tag lk) '(org-activate-tags (1 'org-tag prepend)))
(when (memq 'radio lk) '(org-activate-target-links (1 'org-link t)))
(when (memq 'date lk) '(org-activate-dates (0 'org-date t)))
(when (memq 'footnote lk) '(org-activate-footnote-links))))
(setq org-link-minor-mode-keywords
(list
(when (memq 'tag lk) '(org-activate-tags (1 'org-tag prepend)))
(when (memq 'angle lk) '(org-activate-angle-links (0 'org-link t)))
(when (memq 'plain lk) '(org-activate-plain-links (0 'org-link t)))
(when (memq 'bracket lk) '(org-activate-bracket-links (0 'org-link t)))
(when (memq 'radio lk) '(org-activate-target-links (0 'org-link t)))
(when (memq 'date lk) '(org-activate-dates (0 'org-date t)))
(when (memq 'footnote lk) '(org-activate-footnote-links)))))
We then branch depending on whether we’re entering or exiting the mode:
(if org-link-minor-mode
<<enter-minor-mode>>
<<exit-minor-mode>>)
If we’re already in {{{mode(org-mode)}}}, display a message and switch {{{mode(org-link-minor-mode)}}} off. We need to do it this way as by this point we’ve already entered the minor mode ({{{mode(org-link-minor-mode)}}} is {{{const(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>>)
When we enter the minor mode, we
- add the font lock keywords
- define the keymap that will be active within links
- set the unfontify function
- set up {{{var(org-descriptive-links)}}}
- turn on link display
Add the font-lock specification:
(font-lock-add-keywords nil org-link-minor-mode-keywords t)
Org mode associates the {{{var(org-mouse-map)}}} keymap with links. This becomes active when the mouse or point is over a link.
We can use this to enable {{{key(return)}}} to follow link (and {{{key(tab)}}} to next link, {{{key(backtab)}}} to previous, etc.):
(kill-local-variable 'org-mouse-map)
(setq-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 {{{var(org-mouse-map)}}} like this is a hack. This keymap is set as a text property of links in {{{fn(org-activate-links)}}}, etc. so it’s simpler to co-opt it than to replace those functions.
Make {{{var(org-descriptive-links)}}} local, turning it off. We will switch descriptive links on when we call {{{fn(org-toggle-link-display)}}} below.
(setq-local org-descriptive-links nil)
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):
(setq-local font-lock-unfontify-region-function
'org-link-minor-mode--unfontify-region)
The documentation for {{{fn(font-lock-unfontify-region-function)}}} is a bit sparse but reading {{{fn(org-unfontify-region)}}} at least shows you what it should do.
Finally, we refontify the buffer using {{{fn(org-toggle-link-display)}}}. This will reset {{{var(org-descriptive-links)}}} to {{{const(t)}}}.
(org-toggle-link-display)
Again, we don’t run this code if we’re already in org-mode:
(unless (derived-mode-p 'org-mode)
<<exit-minor-mode-body>>)
Remove all org-link font-lock properties:
(font-lock-remove-keywords nil org-link-minor-mode-keywords)
Turn off link display:
(setq org-descriptive-links t)
(org-toggle-link-display)
Kill the local variables:
(kill-local-variable 'org-descriptive-links)
(kill-local-variable 'org-mouse-map)
(kill-local-variable 'font-lock-unfontify-region-function)
{{{fn(org-unfontify-region)}}} does not remove the {{{prop(help-echo)}}}, {{{prop(htmlize-link)}}} and {{{prop(rear-nonsticky)}}} properties, so I’ve copied that function and added those in.
Note: This looks like a bug in {{{fn(org-unfontify-region)}}}.
We can ignore the {{{prop(fontified)}}} property as that belongs to {{{mode(font-lock-mode)}}}.
(defun org-link-minor-mode--unfontify-region (beg end)
"Remove org-link fontification between BEG and END."
(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)
(if (fboundp 'org-decompose-region)
(org-decompose-region beg end)
(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
htmlize-link t
org-no-flyspell t org-emphasis t))
(org-remove-font-lock-display-properties beg end)))
Note that org-link-minor-mode-unfontify-region
is obsolete.
(defalias 'org-link-minor-mode-unfontify-region 'org-link-minor-mode--unfontify-region)
(make-obsolete 'org-link-minor-mode-unfontify-region 'org-link-minor-mode--unfontify-region
"org-link-minor-mode 0.0.3")
The keymap is defined in case you want to define your own key bindings for this mode. It is not used by {{{mode(org-link-minor-mode)}}} itself.
(defvar org-link-minor-mode-map (make-sparse-keymap)
"Local keymap.")
(make-variable-buffer-local 'org-link-minor-mode-map)
Finally, we add the {{{fn(provide)}}} feature clause so that we can later {{{code((require ‘org-link-minor-mode))}}}.
(provide 'org-link-minor-mode)
Here is the complete source:
<<header>>
<<requires>>
<<declarations-for-byte-code>>
<<org-link-minor-mode--unfontify-region>>
<<keymap>>
<<define-minor-mode>>
<<provide>>
;;; org-link-minor-mode.el ends here