Hi Eric,
Thanks for doing this. I've had some similar code in my config for a
while. I'll share some of it here in case you find it useful in doing
this. You especially might find the org-read-structure-template
function useful.
And here's my version, which also uses hydra. But the function modi/org-template-expand to insert the BEGIN_../END_.. blocks can be reused.
This at least tells that there's a good need to have the easy template do the right thing when it is called with a region selected.
@Adam: Looks like your code is doing a lot more than just that. I'll put that to my list to understand once I get to a computer.
(defun modi/org-template-expand (str &optional lang)
"Expand Org template."
(let (beg old-beg end content)
;; Save restriction to automatically undo the upcoming `narrow-to-region'
(save-restriction
(when (use-region-p)
(setq beg (region-beginning))
(setq end (region-end))
;; Note that regardless of the direction of selection, we will always
;; have (region-beginning) < (region-end).
(save-excursion
;; If `point' is at `end', exchange point and mark so that now the
;; `point' is now at `beg'
(when (> (point) (mark))
(exchange-point-and-mark))
;; Insert a newline if `beg' is *not* at beginning of the line.
;; Example: You have ^abc$ where ^ is bol and $ is eol.
;; "bc" is selected and <e is pressed to result in:
;; a
;; #+BEGIN_EXAMPLE
;; bc
;; #+END_EXAMPLE
(when (/= beg (line-beginning-position))
(electric-indent-just-newline 1)
(setq old-beg beg)
(setq beg (point))
;; Adjust the `end' due to newline
(setq end (+ end (- beg old-beg)))))
(save-excursion
;; If `point' is at `beg', exchange point and mark so that now the
;; `point' is now at `end'
(when (< (point) (mark))
(exchange-point-and-mark))
;; If the `end' position is at the beginning of a line decrement
;; the position by 1, so that the resultant position is eol on
;; the previous line.
(when (= end (line-beginning-position))
(setq end (1- end)))
;; Insert a newline if `point'/`end' is *not* at end of the line.
;; Example: You have ^abc$ where ^ is bol and $ is eol.
;; "a" is selected and <e is pressed to result in:
;; #+BEGIN_EXAMPLE
;; a
;; #+END_EXAMPLE
;; bc
(when (not (looking-at "[[:blank:]]*$"))
(electric-indent-just-newline 1)))
;; Narrow to region so that the text surround the region does
;; not mess up the upcoming `org-try-structure-completion' eval
(narrow-to-region beg end)
(setq content (delete-and-extract-region beg end)))
(insert str)
(org-try-structure-completion)
(when (string= "<s" str)
(cond
(lang
(insert lang)
(forward-line))
((and content (not lang))
(insert "???")
(forward-line))
(t
)))
;; At this point the cursor will be between the #+BEGIN and #+END lines
(when content
(insert content)
(deactivate-mark)))))
(defhydra hydra-org-template (:color blue
:hint nil)
"
org-template: _c_enter _s_rc _e_xample _v_erilog _t_ext _I_NCLUDE:
_l_atex _h_tml _V_erse _m_atlab _L_aTeX: _H_TML:
_a_scii _q_uote _E_macs-lisp _n_im _i_ndex: _A_SCII:
^^ ^^ _S_hell _p_ython ^^ ^^
"
("s" (modi/org-template-expand "<s")) ;#+BEGIN_SRC ... #+END_SRC
("E" (modi/org-template-expand "<s" "emacs-lisp"))
("v" (modi/org-template-expand "<s" "systemverilog"))
("m" (modi/org-template-expand "<s" "matlab"))
("n" (modi/org-template-expand "<s" "nim"))
("S" (modi/org-template-expand "<s" "shell"))
("p" (modi/org-template-expand "<s" "python"))
("t" (modi/org-template-expand "<s" "text"))
("e" (modi/org-template-expand "<e")) ;#+BEGIN_EXAMPLE ... #+END_EXAMPLE
("x" (modi/org-template-expand "<e")) ;#+BEGIN_EXAMPLE ... #+END_EXAMPLE
("q" (modi/org-template-expand "<q")) ;#+BEGIN_QUOTE ... #+END_QUOTE
("V" (modi/org-template-expand "<v")) ;#+BEGIN_VERSE ... #+END_VERSE
("c" (modi/org-template-expand "<c")) ;#+BEGIN_CENTER ... #+END_CENTER
("l" (modi/org-template-expand "<l")) ;#+BEGIN_EXPORT latex ... #+END_EXPORT
("L" (modi/org-template-expand "<L")) ;#+LaTeX:
("h" (modi/org-template-expand "<h")) ;#+BEGIN_EXPORT html ... #+END_EXPORT
("H" (modi/org-template-expand "<H")) ;#+HTML:
("a" (modi/org-template-expand "<a")) ;#+BEGIN_EXPORT ascii ... #+END_EXPORT
("A" (modi/org-template-expand "<A")) ;#+ASCII:
("i" (modi/org-template-expand "<i")) ;#+INDEX: line
("I" (modi/org-template-expand "<I")) ;#+INCLUDE: line
("<" self-insert-command "<")
("o" nil "quit"))
(defun modi/org-template-maybe ()
"Insert org-template if point is at the beginning of the line, or is a
region is selected. Else call `self-insert-command'."
(interactive)
(let ((regionp (use-region-p)))
(if (or regionp
(and (not regionp)
(looking-back "^")))
(hydra-org-template/body)
(self-insert-command 1))))