"Thomas S. Dye" <t...@tsdye.com> writes:

> Eric Abrahamsen writes:
>
>> Rasmus <ras...@gmx.us> writes:
>>
>>> Hi Eric,
>>>
>>> Eric Abrahamsen <e...@ericabrahamsen.net> writes:
>>>
>>>>> Also, Eric, it seems that org-structure-template-alist only supports a
>>>>> single letter for short-hands (the car of an entry in
>>>>> org-structure-template-alist is a char).  I used to have blocks like "<ab"
>>>>> expanding to an "abstract" special-block, which I guess isn’t possible
>>>>> anymore?
>>>>
>>>> I hadn't thought of that. Really, all I ever wanted was to wrap things
>>>> in blocks...
>>>>
>>>> I don't see any reason why org-structure-template-alist couldn't go back
>>>> to using string keys. Then we could use read-string, and wouldn't have
>>>> to have special <TAB> behavior -- a string that didn't exist in the
>>>> alist could just be used literally to make a block.
>>>
>>> I’d prefer that.  For some special blocks, a few characters might makes it
>>> more intuitive, e.g. "def" → "definition", "hyp" → "hypothesis" etc.
>>
>> Here's the simplest solution.
>>
>> There still remains the fact that `org-structure-template-alist' has
>> changed format, and `org-try-structure-completion' no longer exists.
>> That may still annoy some people who were using the internals of the
>> process, but...
>
> Would something like this work?
>
> (defun org-try-structure-completion ()
>   (tempo-complete-tag))

Here's the newest version!

It incorporates Rasmus' org-tempo.el file, with modifications, and
Thomas' suggestion to re-instate `org-try-structure-completion', and,
erm, stardiviner's request to honor
`org-babel-uppercase-example-markers'.

Remaining issues:

1. The "org-include" tempo template doesn't work, for reasons I don't
   understand (I've never used tempo before). Nothing happens when I hit
   <TAB>.
2. Now it seems like there should be completion when prompting for a
   string key. Feature creep! But likely worthwhile feature creep.
3. I've rather rashly renamed the relevant customization options
   `org-structure-block-alist' (for blocks added via
   `org-insert-structure-template') and `org-structure-keyword-alist'
   (for keywords insertable via the tempo system). Perhaps this was a
   bad idea. If it's not a bad idea, maybe
   `org-insert-structure-template' should be renamed `org-insert-block'
   or something like that.
3. Docs need to be updated.

Comments welcome!

Eric

diff --git a/lisp/org-tempo.el b/lisp/org-tempo.el
new file mode 100644
index 000000000..ebe5a26c2
--- /dev/null
+++ b/lisp/org-tempo.el
@@ -0,0 +1,118 @@
+;;; org-tempo.el --- Tempo-style templates for Org -*- 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:
+
+;; Block and structure templates, to replace the previous Org-specific
+;; system.  The old function `org-try-structure-completion' is
+;; provided as a thin wrapper around `tempo-complete-tag', for
+;; backwards compatibility.
+
+;;; Code:
+
+(require 'tempo)
+(require 'cl-lib)
+
+(defvar org-tempo-tags nil
+  "Tempo tags for org-mode")
+
+(defcustom org-structure-keyword-alist
+  '(("L" . "latex")
+    ("H" . "html")
+    ("A" . "ascii")
+    ("i" . "index"))
+  "Keyword templates expanded using the tempo package."
+  :group 'org-tempo
+  :type '(repeat
+	  (cons (string :tag "Key")
+		(string :tag "Template")))
+  :package-version '(Org . "9.2"))
+
+(defun org-tempo-setup ()
+  (tempo-use-tag-list 'org-tempo-tags)
+  (setq tempo-match-finder "^ *\\(<[[:word:]]\\)\\="))
+
+(add-hook 'org-mode-hook 'org-tempo-setup)
+
+(defun org-tempo-add-templates ()
+  "Update all org-tempo templates.
+Goes through `org-structure-block-alist' and
+`org-structure-keyword-alist'."
+  (let ((keys (mapcar (apply-partially #'format "<%s")
+		      (mapcar #'car (append org-structure-block-alist
+					    org-structure-keyword-alist)))))
+    (if (> (length keys)
+           (length (delete-dups keys)))
+	(user-error "Duplicate keys in `org-structure-template-alist' and `org-structure-template-alist-keywords'"))
+    (dolist (key keys)
+      (if (assoc-string key org-tempo-tags)
+	  (setq org-tempo-tags
+		(delete (assoc-string key org-tempo-tags)
+			org-tempo-tags))))
+    (mapc #'org-tempo-add-block org-structure-block-alist)
+    (mapc #'org-tempo-add-keyword org-structure-keyword-alist))
+  (setq tempo-dirty-collection t))
+
+(defun org-tempo-add-block (entry)
+  "Add block entry from `org-structure-block-alist'."
+  (let* ((key (format "<%s" (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 (org-split-string name " ")))
+       >)
+     key
+     (format "Insert a %s block" name)
+     'org-tempo-tags)))
+
+(defun org-tempo-add-keyword (entry)
+  "Add keyword entry from `org-structure-keyword-alist'."
+  (let* ((key (format "<%s" (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
+
+(tempo-define-template
+ "org-include"
+ '("#+include: "
+   (ignore-errors
+     (format "\"%s\" " (file-relative-name (read-file-name "Include file: "))))
+   p >)
+ "<I"
+ "Include keyword"
+ 'org-tempo-tags)
+
+(with-eval-after-load 'org
+  (org-tempo-add-templates)
+  (add-hook 'org-tab-before-tab-emulation-hook
+	    'tempo-complete-tag))
+
+(provide 'org-tempo)
+;;; org-tempo.el ends here
diff --git a/lisp/org.el b/lisp/org.el
index f873f1021..9ceaa2205 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -11856,43 +11856,41 @@ keywords relative to each registered export back-end."
     "PRIORITIES:" "SELECT_TAGS:" "SEQ_TODO:" "SETUPFILE:" "STARTUP:" "TAGS:"
     "TITLE:" "TODO:" "TYP_TODO:" "SELECT_TAGS:" "EXCLUDE_TAGS:"))
 
-(defcustom org-structure-template-alist
-  '((?a . "export ascii")
-    (?c . "center")
-    (?C . "comment")
-    (?e . "example")
-    (?E . "export")
-    (?h . "export html")
-    (?l . "export latex")
-    (?q . "quote")
-    (?s . "src")
-    (?v . "verse"))
+(defcustom org-structure-block-alist
+  '(("a" . "export ascii")
+    ("c" . "center")
+    ("C" . "comment")
+    ("e" . "example")
+    ("E" . "export")
+    ("h" . "export html")
+    ("l" . "export latex")
+    ("q" . "quote")
+    ("s" . "src")
+    ("v" . "verse"))
   "Structure completion elements.
 This is an alist of characters and values.  When
-`org-insert-structure-template' is called, an additional key is
-read.  The key is first looked up in this alist, and the
-corresponding structure is inserted, with \"#+BEGIN_\" and
-\"#+END_\" added automatically."
+`org-insert-structure-template' is called, a string key is read.
+The key is first looked up in this alist, and the corresponding
+structure is inserted, with \"#+BEGIN_\" and \"#+END_\" added
+automatically."
   :group 'org-completion
   :type '(repeat
-	  (cons (character :tag "Key")
+	  (cons (string :tag "Key")
 		(string :tag "Template")))
   :package-version '(Org . "9.2"))
 
 (defun org-insert-structure-template (type)
   "Insert a block structure of the type #+begin_foo/#+end_foo.
-First read a character, which can be one of the keys in
-`org-structure-template-alist'.  When it is <TAB>, prompt the
-user for a string to use.  With an active region, wrap the region
-in the block.  Otherwise, insert an empty block."
+First read a string, which is used as a lookup key in
+`org-structure-block-alist' or, failing that, used literally.
+With an active region, wrap the region in the block.  Otherwise,
+insert an empty block."
   (interactive
    (list
-    (let* ((key (read-key "Key: "))
+    (let* ((key (read-string "Block type: "))
 	   (struct-string
-	    (or (cdr (assq key org-structure-template-alist))
-		(and (= key ?\t)
-		     (read-string "Structure type: "))
-		(user-error "`%c' has no structure definition" key))))
+	    (or (cdr (assoc-string key org-structure-block-alist))
+		key)))
       struct-string)))
   (let* ((region? (use-region-p))
 	 (s (if region? (region-beginning) (point)))
@@ -11923,6 +11921,10 @@ in the block.  Otherwise, insert an empty block."
       (end-of-line))
     (set-marker e nil)))
 
+;; For backward compatibility with the previous system.
+(defun org-try-structure-completion ()
+  (tempo-complete-tag))
+
 ;;;; TODO, DEADLINE, Comments
 
 (defun org-toggle-comment ()

Reply via email to