Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Emacs org-mode, how to refile highlighted text under an org heading?

In Emacs org-mode, is there a way to automatically refile highlighted text under an org heading? i.e. to cut the highlighted text and automatically paste it under the org-heading of my choice?

You could call it org-refile-region. Similar to org-refile, but to refile not the entire subtree, but only the highlighted region under any heading in the current document.

UPDATE:

Ideally this functionality would be independent of the org-agenda files used by org-refile, so as to avoid displaying irrelevant headings as possible targets.

Currently this is doable by doing: 1. select text 2. cut 3. other-window 4. navigate to desired target heading 5. paste text 6. other window

The proposed new function would make this much more efficient: 1. select text 2. org-refile-region 3. choose target

The most useful form of this would allow you to choose a target from among any currently open documents. My use case involves selecting text from one buffer and refiling it from among org-headings in another buffer, i.e. moving text from a source document displayed in one window and refiling to targets within the hierarchy of a target document displayed in another window, like so:

like image 913
incandescentman Avatar asked Oct 21 '22 03:10

incandescentman


1 Answers

If you are using emacs 24.1 or later, you can try

(setq org-refile-active-region-within-subtree t)

which will almost do what you want, but turn the line in which you have highlighted text (the emacs term is "active region") into a headline.

If you want to move the text you have highlighted to another heading, you have to extend org-mode. Fortunately, org provides the tools you need. Here is an example:

(defvar org-refile-region-format "\n%s\n")

(defvar org-refile-region-position 'top
  "Where to refile a region. Use 'bottom to refile at the
end of the subtree. ")

(defun org-refile-region (beg end copy)
  "Refile the active region.
If no region is active, refile the current paragraph.
With prefix arg C-u, copy region instad of killing it."
  (interactive "r\nP")
  ;; mark paragraph if no region is set
  (unless (use-region-p)
    (setq beg (save-excursion
                (backward-paragraph)
                (skip-chars-forward "\n\t ")
                (point))
          end (save-excursion
                (forward-paragraph)
                (skip-chars-backward "\n\t ")
                (point))))
  (let* ((target (save-excursion (org-refile-get-location)))
         (file (nth 1 target))
         (pos (nth 3 target))
         (text (buffer-substring-no-properties beg end)))
    (unless copy (kill-region beg end))
    (deactivate-mark)
    (with-current-buffer (find-file-noselect file)
      (save-excursion
        (goto-char pos)
        (if (eql org-refile-region-position 'bottom)
            (org-end-of-subtree)
          (org-end-of-meta-data-and-drawers))
        (insert (format org-refile-region-format text))))))

We use org-refile-get-location to apply the org refiling mechanism and extract the file and the location. Then we go to that location and insert the copied text. Two variables added for convenience.

org-refile-targets lets you control which files to consider, e.g.:

nil  ;; only the current file
'((org-agenda-files :maxlevel . 2)) ;; all agenda files, 1st/2nd level
'((org-files-list :maxlevel . 4)) ;; all agenda and all open files
'((my-org-files-list :maxlevel . 4)) ;; all files returned by `my-org-files-list'

To restrict refiling to the currently open org buffers, define a function

(defun my-org-files-list ()
  (mapcar (lambda (buffer)
            (buffer-file-name buffer))
          (org-buffer-list 'files t)))

And then either

(setq org-refile-targets '((my-org-files-list :maxlevel . 4)))

or use

M-x customize-option <ret> org-refile-targets

select "Function" from the "value menu", and type my-org-files-list

like image 132
olaf b Avatar answered Nov 17 '22 07:11

olaf b