emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Adam Porter <adam@alphapapa.net>
To: emacs-orgmode@gnu.org
Subject: Re: function for inserting a block
Date: Sat, 02 Sep 2017 21:21:08 -0500	[thread overview]
Message-ID: <87h8wked4b.fsf@alphapapa.net> (raw)
In-Reply-To: 877exghblx.fsf@ericabrahamsen.net

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.

Note that some of this uses s and hydra, which obviously isn't suitable
for Org proper, but that could be fixed.

#+BEGIN_SRC elisp
(defun ap/org-copy-block (prefix)
    "Copy current \"#+BEGIN_...\" block to the kill-ring."
    (interactive "p")
    (kill-new (ap/org-block-contents (>= prefix 4))))

  (defun ap/org-block-contents (&optional whole)
    "Return contents of current \"BEGIN_...\" block.
When WHOLE is non-nil, include enclosing meta lines."
    (let ((bounds (ap/org-block-boundaries (not whole))))
      (buffer-substring-no-properties (car bounds) (cdr bounds))))

  (defun ap/org-block-boundaries (&optional contents)
    "Return (BEGINNING . END) of current \"#+BEGIN_...\" block.
    If CONTENTS is non-nil, return the boundaries of the block's
    contents rather than the entire block."
    (let ((case-fold-search t)
          (re "#\\+begin_\\(\\sw+\\)")
          block-beg block-end contents-beg contents-end)
      (save-excursion
        ;; Get block
        (unless (looking-at re)
          ;; If point is in the middle of the "#+BEGIN...",
          ;; `search-backward-regexp' fails, so go to end of line first.
          (end-of-line)
          (condition-case nil
              (search-backward-regexp re)
            (error "Not in a block.")))
        (setq block-beg (point))
        (setq block-end (search-forward-regexp (concat (rx bol (optional (1+ space)) "#+end_") (match-string 1))))
        (goto-char block-beg)
        (forward-line)
        (setq contents-beg (point))
        (goto-char block-end)
        (end-of-line 0)
        (setq contents-end (point)))
      (if contents
          `(,contents-beg . ,contents-end)
        `(,block-beg . ,block-end))))

  (defun ap/org-read-structure-template ()
    "Read org-mode structure template with completion.  Returns template string."
    (let* ((templates (map 'list 'second org-structure-template-alist))
           (prefixes (map 'list (lambda (tp)
                                  ;; Get template and pre-whitespace prefix for completion
                                  (reverse (s-match (rx (group
                                                         (1+ (not (any "\n" space))))
                                                        (1+ anything))
                                                    tp)))
                          templates))
           (prefix (completing-read "Template: " prefixes nil t))
           (template (second (assoc prefix prefixes))))
      template))

  (defun ap/org-in-block-p ()
    "Non-nil when point belongs to a block.

Return first block name matched, or nil.  Beware that in case of
nested blocks, the returned name may not belong to the closest
block from point."
    (save-match-data
      (let ((case-fold-search t)
            (lim-up (save-excursion (outline-previous-heading)))
            (lim-down (save-excursion (outline-next-heading))))
        (org-between-regexps-p "^[ \t]*#\\+begin_" "^[ \t]*#\\+end_"
                               lim-up lim-down))))

  (defun ap/org-indent-src-block ()
    (interactive)
    (when (ap/org-in-block-p)
      (org-edit-src-code)
      (insert (replace-regexp-in-string
               " +" " " (delete-and-extract-region (point-min) (point-max))))
      (ap/indent-whole-buffer)
      (whitespace-cleanup)
      (org-edit-src-exit)))

  (defun ap/org-insert-structure-template-or-enclose-region ()
    "Insert structure block template.  When region is active, enclose region in block."
    (require 's)
    (interactive)
    (let* ((template (ap/org-read-structure-template))
           (text "")
           enclosed-text)
      (when (use-region-p)
        (setq text (buffer-substring-no-properties (region-beginning) (region-end)))
        (delete-region (region-beginning) (region-end)))
      (setq enclosed-text (s-replace "?" text template))
      (insert enclosed-text)
      (backward-char (- (length enclosed-text) (length (s-shared-start enclosed-text template))))))

  (defun ap/org-change-block-types ()
    "Change the type of org-mode block at point, or blocks in region."
    (interactive)
    (if (use-region-p)
        (progn
          (deactivate-mark)
          (goto-char (region-beginning))
          (while (re-search-forward  "^ *#\\+BEGIN_" (region-end) nil)
            (ap/org-change-block-type-at-point)))
      (ap/org-change-block-type-at-point)))

  (defun ap/org-change-block-type-at-point ()
    "Change type of org-mode block at point."
    (interactive)
    (unless (ap/org-in-block-p)
      (error "Not in an org-mode block."))
    (let* ((template (ap/org-read-structure-template))
           (case-fold-search t)
           (re "#\\+begin_\\(\\sw+\\)")
           (block-bounds (ap/org-block-boundaries))
           (block-beg (car block-bounds))
           (block-end (cdr block-bounds))
           (contents (ap/org-block-contents))
           new-block)
      ;; Insert contents into template
      (setq new-block (replace-regexp-in-string (rx "?") contents template))
      ;; Remove extra newline from e.g. SRC blocks
      (setq new-block (replace-regexp-in-string (rx "\n\n#+END") "\n#+END" new-block))
      ;; Replace old block with new one
      (goto-char block-beg)
      (delete-region block-beg block-end)
      (insert new-block)
      ;; Position cursor (especially for SRC blocks, allowing the user to enter the type)
      (search-backward-regexp re)
      (search-forward-regexp (rx space))))

;; From https://github.com/abo-abo/hydra/wiki/Org-mode-block-templates
;; With "<" bound to ap/hydra-org-expand-block-template in org-mode-map:

(defhydra hydra-org-block-template (:color blue :hint nil)
  "
   _c_enter _q_uote _e_macs-lisp _L_aTeX:
   _l_atex _E_xample _p_erl _i_ndex:
   _a_scii _v_erse _P_erl tangled _I_NCLUDE:
   _s_rc ^ ^ plant_u_ml _H_TML:
   _h_tml ^ ^ ^ ^ _A_SCII:
   "
  ("s" (ap/org-hydra-expand-template "<s"))
  ("E" (ap/org-hydra-expand-template "<e"))
  ("q" (ap/org-hydra-expand-template "<q"))
  ("v" (ap/org-hydra-expand-template "<v"))
  ("c" (ap/org-hydra-expand-template "<c"))
  ("l" (ap/org-hydra-expand-template "<l"))
  ("h" (ap/org-hydra-expand-template "<h"))
  ("a" (ap/org-hydra-expand-template "<a"))
  ("L" (ap/org-hydra-expand-template "<L"))
  ("i" (ap/org-hydra-expand-template "<i"))
  ("e" (ap/org-hydra-expand-template "<s" "elisp"))
  ("p" (ap/org-hydra-expand-template "<s" "perl"))
  ("u" (ap/org-hydra-expand-template "<s" "plantuml :file CHANGE.png"))
  ("P" (progn
         (insert "#+HEADERS: :results output :exports both :shebang \"#!/usr/bin/env perl\"\n")
         (ap/org-hydra-expand-template "<s" "perl")))
  ("I" (ap/org-hydra-expand-template "<I"))
  ("H" (ap/org-hydra-expand-template "<H"))
  ("A" (ap/org-hydra-expand-template "<A"))
  ("<" self-insert-command "ins")
  ("o" nil "quit"))

(defun ap/hydra-org-expand-block-template ()
    (interactive)
    (if (or (use-region-p) (looking-back "^"))
        (hydra-org-block-template/body)
      (self-insert-command 1)))

(defun ap/org-hydra-expand-template (str &optional mod)
  "Expand org template."
  (let (text)
    (when (use-region-p)
      (setq text (buffer-substring (region-beginning) (region-end)))
      (delete-region (region-beginning) (region-end)))
    (insert str)
    (org-try-structure-completion)
    (when mod (insert mod) (forward-line))
    (when text (insert text))))
#+END_SRC

  reply	other threads:[~2017-09-03  2:22 UTC|newest]

Thread overview: 104+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-09-03  0:25 function for inserting a block Eric Abrahamsen
2017-09-03  2:21 ` Adam Porter [this message]
2017-09-03  3:06   ` Kaushal Modi
2017-09-03  3:34     ` Eric Abrahamsen
2017-09-03  8:10 ` Nicolas Goaziou
2017-09-03  8:19   ` Adam Porter
2017-09-03  8:23     ` Nicolas Goaziou
2017-09-03 15:56   ` Eric Abrahamsen
2017-09-03 18:31     ` Josiah Schwab
2017-09-03 19:28       ` Eric Abrahamsen
2017-09-03 20:26         ` Josiah Schwab
2017-09-03 20:44           ` Eric Abrahamsen
2017-09-08 18:52     ` Eric Abrahamsen
2017-09-10 12:44       ` Nicolas Goaziou
2017-09-10 18:39         ` Eric Abrahamsen
2017-09-29 20:09           ` Nicolas Goaziou
2017-09-30 20:26             ` Eric Abrahamsen
2017-10-05 14:47               ` Nicolas Goaziou
2017-10-07 20:03                 ` Eric Abrahamsen
2017-10-14 10:52                   ` Nicolas Goaziou
2017-10-16 19:46                     ` Eric Abrahamsen
2017-10-16 19:59                       ` Eric Abrahamsen
2017-10-17  7:46                       ` Nicolas Goaziou
2017-10-17 16:27                         ` Eric Abrahamsen
2017-10-17 21:33                           ` Nicolas Goaziou
2017-10-17 21:43                             ` Eric Abrahamsen
2017-10-17 22:03                               ` Eric Abrahamsen
2017-10-18  6:45                                 ` Carsten Dominik
2017-10-18 14:58                                   ` Eric Abrahamsen
2017-10-19 15:47                                     ` Carsten Dominik
2017-10-20 18:04                                       ` Eric Abrahamsen
2017-10-20 18:39                                         ` Kaushal Modi
2017-10-20 19:02                                           ` Kaushal Modi
2017-10-20 21:15                                             ` Eric Abrahamsen
2017-10-20 21:13                                           ` Eric Abrahamsen
2017-10-20 21:43                                             ` Kaushal Modi
2017-10-21 11:30                                               ` Xebar Saram
2017-10-21 11:59                                                 ` Marco Wahl
2017-10-21 13:32                                                   ` Xebar Saram
2017-10-21 15:56                                               ` Eric Abrahamsen
2017-10-23 10:52                                               ` Kaushal Modi
2017-10-23 14:00                                                 ` Carsten Dominik
2017-10-23 14:46                                                   ` Kaushal Modi
2017-10-23 15:11                                                 ` Eric Abrahamsen
2017-10-23 16:55                                                   ` Nicolas Goaziou
2017-10-24  0:18                                                     ` Eric Abrahamsen
2017-10-24  0:20                                                       ` Eric Abrahamsen
2017-10-24 12:10                                                       ` Nicolas Goaziou
2017-10-28 22:27                                                         ` Eric Abrahamsen
2017-10-30 11:05                                                           ` Nicolas Goaziou
2017-10-30 15:08                                                             ` Eric S Fraga
2017-10-30 16:22                                                             ` Eric Abrahamsen
2017-10-30 17:57                                                               ` Eric Abrahamsen
2017-11-05  9:06                                                                 ` Nicolas Goaziou
2017-11-05 14:24                                                                   ` Kaushal Modi
2017-11-05 14:37                                                                     ` Kaushal Modi
2017-11-06 13:48                                                                       ` Nicolas Goaziou
2017-11-06 16:23                                                                         ` Kaushal Modi
2017-11-05 21:25                                                                   ` Eric Abrahamsen
2017-12-10  9:36                                                           ` Thorsten Jolitz
2017-10-22  9:54                                             ` Nicolas Goaziou
2017-10-22 17:49                                               ` Eric Abrahamsen
2017-11-08 11:20                                                 ` Bastien
2017-11-08 11:44                                                   ` Nicolas Goaziou
2017-11-08 12:14                                                     ` Bastien
2017-11-08 12:25                                                       ` Restore old easy template feature (Re: function for inserting a block) Kaushal Modi
2017-11-08 12:43                                                         ` Kaushal Modi
2017-11-08 14:08                                                           ` Bastien Guerry
2017-12-18 22:07                                                             ` Matt Price
2017-12-19  1:44                                                               ` Eric Abrahamsen
2017-12-19 10:04                                                               ` Rasmus
2017-12-19 17:49                                                                 ` Matt Price
2017-11-08 13:35                                                         ` Nicolas Goaziou
2017-11-08 13:34                                                       ` function for inserting a block Nicolas Goaziou
2017-11-08 14:34                                                         ` Bastien Guerry
2017-11-08 16:01                                                           ` Eric Abrahamsen
2017-11-08 16:33                                                       ` William Denton
2017-11-08 14:07                                                     ` Rasmus
2017-11-08 17:09                                                       ` Berry, Charles
2017-11-08 17:28                                                         ` Nicolas Goaziou
2017-11-08 18:24                                                         ` Thomas S. Dye
2017-11-08 18:51                                                           ` Takaaki Ishikawa
2017-11-08 20:10                                                             ` Eric Abrahamsen
2017-11-08 22:28                                                             ` Nicolas Goaziou
2017-11-09  4:31                                                               ` Thomas S. Dye
2017-11-09  7:55                                                                 ` Carsten Dominik
2017-11-12  4:35                                                                   ` Matt Lundin
2017-11-12  6:08                                                                     ` numbchild
2017-11-09 14:46                                                               ` Rasmus
2017-11-09 16:11                                                                 ` Rasmus
2017-11-09 16:50                                                                   ` Eric Abrahamsen
2017-11-10  9:31                                                                     ` Rasmus
2017-11-10 17:27                                                                       ` Eric Abrahamsen
2017-11-11 16:51                                                                         ` Thomas S. Dye
2017-11-14 21:36                                                                           ` Eric Abrahamsen
2017-11-15 13:13                                                                             ` numbchild
2017-11-15 16:24                                                                               ` Eric Abrahamsen
2017-11-17 16:19                                                                                 ` numbchild
2017-11-17 19:14                                                                                   ` Eric Abrahamsen
2017-11-18  0:09                                                                                     ` numbchild
2017-11-20 13:40                                                                             ` Rasmus
2017-11-20 16:49                                                                               ` Eric Abrahamsen
2017-11-11  4:13                                                                       ` stardiviner
     [not found] <mailman.107.1510246818.12116.emacs-orgmode@gnu.org>
2017-11-10  4:19 ` James Harkins

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87h8wked4b.fsf@alphapapa.net \
    --to=adam@alphapapa.net \
    --cc=emacs-orgmode@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).