summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Porter <adam@alphapapa.net>2017-08-12 15:41:17 -0500
committerAdam Porter <adam@alphapapa.net>2017-08-12 15:47:07 -0500
commitf4c45d329a31870fb3c927e50dd2561c33ac78a6 (patch)
tree00eb6f7c3e55c7128ffb38732499463426100fca
parent0ed6408f18bf13840f6f57638f86c3b9dfe4a07a (diff)
avy.el: Add org-mode commands for jumping to and refiling headings
* (avy-org-refile-as-child): Refile current heading to a heading selected with Avy. * (avy-org-goto-heading-timer): Jump to a heading selected with Avy. Like avy-goto-char-timer, but for Org headings. * (avy--read-string-with-timeout): Read a string from the minibuffer with a timeout. Basically factored out of avy-goto-char-timer.
-rw-r--r--README.md4
-rw-r--r--avy.el50
2 files changed, 54 insertions, 0 deletions
diff --git a/README.md b/README.md
index 5a4542b..8961ff0 100644
--- a/README.md
+++ b/README.md
@@ -80,6 +80,10 @@ After <kbd>M-g e</kbd>:
![avy-goto-word-0](http://oremacs.com/download/avi-goto-word-0.png)
+### Org-mode commands
+
+ * `avy-org-goto-heading-timer`: Type part of an Org heading. When you stop typing, if only one heading on the screen matches, it will be jumped to; if more than one matches, you can jump to a heading with Avy. This is like `avy-goto-char-timer` but for Org headings.
+ * `avy-org-refile-as-child`: With point in an entry you want to refile, run this command, select a heading with Avy, and the entry will be refiled as its first child heading. This makes it quick and easy to refile to headings that are visible on-screen, even to other windows or buffers.
### Other commands
diff --git a/avy.el b/avy.el
index 84d23dc..0eabc4c 100644
--- a/avy.el
+++ b/avy.el
@@ -538,6 +538,56 @@ multiple DISPLAY-FN invokations."
(funcall avy-handler-function char))))
(cdar alist))))
+;; ** Org-mode
+
+(defun avy-org-refile-as-child ()
+ "Refile current heading as first child of heading selected with `avy.'"
+ ;; Inspired by `org-teleport': http://kitchingroup.cheme.cmu.edu/blog/2016/03/18/Org-teleport-headlines/
+ (interactive)
+ (let ((rfloc (save-excursion
+ (let* ((org-reverse-note-order t)
+ (pos (avy-with avy-goto-line
+ (avy--generic-jump (rx bol (1+ "*") (1+ space))
+ nil avy-style)
+ (point)))
+ (filename (buffer-file-name (or (buffer-base-buffer (current-buffer))
+ (current-buffer)))))
+ (list nil filename nil pos)))))
+ ;; org-refile must be called outside of the excursion
+ (org-refile nil nil rfloc)))
+
+(defun avy-org-goto-heading-timer (&optional arg)
+ "Read one or many characters and jump to matching Org headings.
+The window scope is determined by `avy-all-windows' (ARG negates it)."
+ (interactive "P")
+ (let* ((avy-all-windows (if arg
+ (not avy-all-windows)
+ avy-all-windows))
+ (input (avy--read-string-with-timeout))
+ (regexp (rx-to-string `(seq bol (1+ "*") (1+ space) (0+ not-newline)
+ ,input (0+ not-newline) eol))))
+ (avy-with avy-goto-char-timer
+ (avy--process (avy--regex-candidates regexp)
+ (avy--style-fn avy-style)))))
+
+(defun avy--read-string-with-timeout ()
+ "Read string from minibuffer with a timeout."
+ ;; It's a shame that only `read-char' has the timeout option, so we
+ ;; have to do this funky loop ourselves, instead of
+ ;; e.g. `read-string' with a timeout.
+ (cl-loop with charnum
+ with string = ""
+ while (not (equal 13 charnum))
+ for charnum = (read-char (format "Prompt: %s" string )
+ t
+ (unless (string-empty-p string)
+ avy-timeout-seconds))
+ if (and charnum
+ (not (equal 13 charnum)))
+ concat (make-string 1 charnum) into string
+ else do (setq charnum 13)
+ finally return string))
+
;;** Rest
(defun avy-window-list ()
"Return a list of windows depending on `avy-all-windows'."