diff options
author | Rasmus <rasmus@gmx.us> | 2017-12-05 11:33:59 +0100 |
---|---|---|
committer | Rasmus <rasmus@gmx.us> | 2017-12-08 00:29:08 +0100 |
commit | 94f1a5843826ab332b601397aedb1f2b052fb0c0 (patch) | |
tree | 64d2bcb096f37e2394ae713ab091a596fe9f9f27 | |
parent | d435c75f543cce08b578a399c531a28c37a48b39 (diff) | |
download | org-mode-94f1a5843826ab332b601397aedb1f2b052fb0c0.tar.gz |
org-tempo.el: New file for expansion of templates
* lisp/org-tempo.el: New file.
* doc/org.texi (Structure templates):
* lisp/org.el (org-modules): Add org-tempo.
* testing/lisp/test-org-tempo.el: New file.
-rw-r--r-- | doc/org.texi | 19 | ||||
-rw-r--r-- | etc/ORG-NEWS | 4 | ||||
-rw-r--r-- | lisp/org-tempo.el | 164 | ||||
-rw-r--r-- | lisp/org.el | 1 | ||||
-rw-r--r-- | testing/lisp/test-org-tempo.el | 75 |
5 files changed, 261 insertions, 2 deletions
diff --git a/doc/org.texi b/doc/org.texi index 5becb01..8a54ca2 100644 --- a/doc/org.texi +++ b/doc/org.texi @@ -11948,9 +11948,13 @@ options can be configured via @code{org-html-mathjax-options}, or in the buffer. For example, with the following settings, @smallexample #+HTML_MATHJAX: align: left indent: 5em tagside: left font: Neo-Euler +#+HTML_MATHJAX: cancel.js noErrors.js @end smallexample equation labels will be displayed on the left margin and equations will be -five ems from the left margin. +five ems from the left margin. In addition, it loads the two MathJax +extensions @samp{cancel.js} and @samp{noErrors.js}@footnote{See +@uref{http://docs.mathjax.org/en/latest/tex.html#tex-extensions, TeX and +LaTeX extensions} in the @uref{http://docs.mathjax.org, MathJax manual} to learn about extensions.}. @noindent See the docstring of @code{org-html-mathjax-options} for all supported variables. The MathJax @@ -17396,6 +17400,19 @@ the key is @key{TAB}, the user is prompted to enter a type. Available structure types are defined in @code{org-structure-template-alist}, see the docstring for adding or changing values. +@cindex Tempo +@cindex Template expansion +@cindex template insertion +@cindex insertion, of templates +@vindex org-tempo-keywords-alist +@vindex org-structure-template-alist +Org Tempo expands snippets to structures defined in +@code{org-structure-template-alist} and @code{org-tempo-keywords-alist}. For +example, @code{org-tempo} expands @kbd{< s @key{TAB}} to a code block. +Enable it by customizing @code{org-modules} or add @code{(require +'org-tempo)} to your Emacs init file@footnote{For more information, please +refer to the commentary section in @file{org-tempo.el}.}. + @multitable @columnfractions 0.2 0.8 @item @kbd{c} @tab @samp{#+BEGIN_CENTER} @item @kbd{C} @tab @samp{#+BEGIN_COMMENT} diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 66865ff..9d6c91e 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -72,6 +72,8 @@ document, use =shrink= value instead, or in addition to align: #+END_EXAMPLE ** New features +*** ~org-tempo~ may used for snippet expansion of structure template. +See manual and commentary in ~org-tempo.el~ for details. *** Exclude unnumbered headlines from table of contents Set their =UNNUMBERED= property to the special =notoc= value. See manual for details. @@ -167,7 +169,7 @@ See docstring for details. ** Removed functions *** ~org-try-structure-completion~ - +=org-tempo= may be used as a replacement. ** Removed variables *** org-babel-use-quick-and-dirty-noweb-expansion diff --git a/lisp/org-tempo.el b/lisp/org-tempo.el new file mode 100644 index 0000000..7c37c9f --- /dev/null +++ b/lisp/org-tempo.el @@ -0,0 +1,164 @@ +;;; org-tempo.el --- Template expansion for Org structures -*- lexical-binding: t; -*- + +;; Copyright (C) 2017 Free Software Foundation, Inc. +;; +;; Author: Rasmus Pank Roulund <emacs at pank dot eu> +;; Keywords: outlines, hypermedia, calendar, wp +;; Homepage: http://orgmode.org +;; +;; This file is part of GNU Emacs. +;; +;; GNU Emacs 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 of the License, or +;; (at your option) any later version. + +;; GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. +;; +;;; Commentary: +;; +;; Org Tempo reimplements completions of structure template before +;; point like `org-try-structure-completion' in Org v9.1 and earlier. +;; For example, strings like "<e" at the beginning of the line will be +;; expanded to an example block. +;; +;; All blocks defined in `org-structure-template-alist' are added as +;; Org Tempo shortcuts, in addition to keywords defined in +;; `org-tempo-keywords-alist'. +;; +;; `tempo' can also be used to define more sophisticated keywords +;; completions. See the section "Additional keywords" below for +;; additional details. +;; +;;; Code: + +(require 'tempo) +(require 'cl-lib) + + +(defgroup org-tempo nil + "Options for template expansion of Org structures" + :tag "Org structure" + :group 'org) + +(defvar org-tempo-tags nil + "Tempo tags for org-mode") + +(defcustom org-tempo-keywords-alist + '((?L . "latex") + (?H . "html") + (?A . "ascii") + (?i . "index")) + "Keyword completion elements. + +Like `org-structure-template-alist' this alist of KEY characters +and KEYWORD. The tempo snippet \"<KEY\" is expand to the KEYWORD +value. + +For example \"<l\" at the beginning of a line is expanded to +#+latex:" + :group 'org-tempo + :type '(repeat (cons (character :tag "Key") + (string :tag "Keyword"))) + :package-version '(Org . "9.2")) + + + +;;; Org Tempo functions and setup. + +(defun org-tempo-setup () + (org-tempo-add-templates) + (tempo-use-tag-list 'org-tempo-tags) + (setq-local tempo-match-finder "^ *\\(<[[:word:]]\\)\\=")) + +(defun org-tempo-add-templates () + "Update all Org Tempo templates. + +Goes through `org-structure-template-alist' and +`org-tempo-keywords-alist'." + (let ((keys (mapcar (lambda (pair) (format "<%c" (car pair))) + (append org-structure-template-alist + org-tempo-keywords-alist)))) + ;; Check for duplicated snippet keys and warn if any are found. + (when (> (length keys) (length (delete-dups keys))) + (warn + "Duplicated keys in `org-structure-template-alist' and `org-tempo-keywords-alist'")) + + ;; Remove any keys already defined in case they have been updated. + (mapc (lambda (key) + (if (assoc-string key org-tempo-tags) + (setq org-tempo-tags + (delete (assoc-string key org-tempo-tags) + org-tempo-tags)))) + keys) + (mapc #'org-tempo-add-block org-structure-template-alist) + (mapc #'org-tempo-add-keyword org-tempo-keywords-alist))) + +(defun org-tempo-add-block (entry) + "Add block entry from `org-structure-template-alist'." + (let* ((key (format "<%c" (car entry))) + (name (cdr entry))) + (tempo-define-template (format "org-%s" (replace-regexp-in-string " " "-" name)) + `(,(format "#+begin_%s " name) p '> n n + ,(format "#+end_%s" (car (split-string name " "))) + >) + key + (format "Insert a %s block" name) + 'org-tempo-tags))) + +(defun org-tempo-add-keyword (entry) + "Add keyword entry from `org-tempo-keywords-alist'." + (let* ((key (format "<%c" (car entry))) + (name (cdr entry))) + (tempo-define-template (format "org-%s" (replace-regexp-in-string " " "-" name)) + `(,(format "#+%s: " name) p '>) + key + (format "Insert a %s keyword" name) + 'org-tempo-tags))) + +;;; Additional keywords + +(defun org-tempo--include-file () + "Ask for file name and take care of quit" + (let* ((inhibit-quit t)) + (unless (with-local-quit + (prog1 t + (insert + (format "#+include: \"%s\" " (file-relative-name + (read-file-name "Include file: ")))))) + (insert "<I") + (setq quit-flag nil)))) + +(tempo-define-template "org-include" + '((org-tempo--include-file) + p >) + "<I" + "Include keyword" + 'org-tempo-tags) + + +;;; Setup of Org Tempo +;; +;; Org Tempo is set up with each new Org buffer and potentially in the +;; current Org buffer. +;; +;; Tempo templates can only be added after Org is loaded as +;; `org-structure-template-alist' must be loaded. + +(add-hook 'org-mode-hook 'org-tempo-setup) +(add-hook 'org-tab-before-tab-emulation-hook + 'tempo-complete-tag) +(when (eq major-mode 'org-mode) (org-tempo-setup)) + +(eval-after-load 'org + '(org-tempo-add-templates)) + +(provide 'org-tempo) + +;;; org-tempo.el ends here diff --git a/lisp/org.el b/lisp/org.el index f77cd62..a5c1182 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -706,6 +706,7 @@ For export specific modules, see also `org-export-backends'." (const :tag " mouse: Additional mouse support" org-mouse) (const :tag " protocol: Intercept calls from emacsclient" org-protocol) (const :tag " rmail: Links to RMAIL folders/messages" org-rmail) + (const :tag " tempo: Fast completion for structures" org-tempo) (const :tag " w3m: Special cut/paste from w3m to Org mode." org-w3m) (const :tag "C annotate-file: Annotate a file with org syntax" org-annotate-file) diff --git a/testing/lisp/test-org-tempo.el b/testing/lisp/test-org-tempo.el new file mode 100644 index 0000000..060a7da --- /dev/null +++ b/testing/lisp/test-org-tempo.el @@ -0,0 +1,75 @@ +;;; test-org-tempo.el --- Tests for test-org-tempo.el -*- lexical-binding: t; -*- + +;; Copyright (C) 2017 Rasmus Pank Roulund + +;; Author: Rasmus Pank Roulund <emacs at pank dot eu> + +;; This file is not part of GNU Emacs. + +;; This program 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 of the License, or +;; (at your option) any later version. + +;; This program 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/>. + +;;; Code: + +(require 'org-tempo) + +(unless (featurep 'org-temp) + (signal 'missing-test-dependency "org-tempo")) + +(ert-deftest test-org-tempo/completion () + "Test that blocks and keywords are expanded correctly by org-tempo." + ;; Tempo completion should recognize snippet keywords and expand with tab + (should + (equal (org-test-with-temp-text "<L<point>" + (org-tempo-setup) + (tempo-complete-tag) + (buffer-string)) + "#+latex: ")) + ;; Tempo completion should recognize snippet Blocks + (should + (equal (org-test-with-temp-text "<l<point>" + (org-tempo-setup) + (call-interactively 'org-cycle) + (buffer-string)) + "#+begin_export latex \n\n#+end_export")) + ;; Tab should work for expansion. + (should + (equal (org-test-with-temp-text "<L<point>" + (org-tempo-setup) + (tempo-complete-tag) + (buffer-string)) + (org-test-with-temp-text "<L<point>" + (org-tempo-setup) + (org-cycle) + (buffer-string)))) + ;; Tempo should not expand unknown snippets + (equal (org-test-with-temp-text "<k" + (org-tempo-setup) + (call-interactively 'org-cycle) + (buffer-string)) + "<k")) + +(ert-deftest test-org-tempo/add-new-templates () + "Test that new structures and keywords are added correctly." + ;; Check that deleted keys are not kept + (should + (let ((org-structure-template-alist '((?n . "new_block")))) + (org-tempo-add-templates) + (assoc "<n" org-tempo-tags))) + (should + (let ((org-tempo-keywords-alist '((?N . "new_keyword")))) + (org-tempo-add-templates) + (assoc "<N" org-tempo-tags)))) + +(provide 'test-org-tempo) +;;; test-org-tempo.el end here |