Skip to content
Yuto SASAKI edited this page Jul 21, 2020 · 7 revisions

Writing your own avy commands

This page describes how to write your own avy-enabled commands that jump to custom things.

Jumping to conditionals in Elisp

(defun avy-goto-conditional ()
  (interactive)
  (avy--generic-jump "\\s(\\(if\\|cond\\|when\\|unless\\)\\b" nil 'pre))
(global-set-key (kbd "M-g c") 'avy-goto-conditional)

Jumping to an open paren

(defun avy-goto-parens ()
  (interactive)
  (let ((avy-command this-command))   ; for look up in avy-orders-alist
    (avy-jump "(+")))
(add-to-list 'avy-orders-alist '(avy-goto-parens . avy-order-closest))
(global-define-key (kbd "s-p") 'avy-goto-parens)

Jumping to org headings

(defun avy-org-same-level (&optional all)
  "Go to any org heading of the same level as the current one.

By default, choices are limited to headings under common
subheading, but if called with a prefix argument, will be
buffer-global."
  (interactive "P")
  (let ((org-level (org-current-level)))
    (avy--generic-jump
     (format "^%s "
             (regexp-quote
              (make-string org-level ?*)))
     nil
     'pre
     (unless (or all (= org-level 1))
       (save-excursion
         (outline-up-heading 1)
         (point)))
     (unless (or all (= org-level 1))
       (save-excursion
         (outline-up-heading 1)
         (org-end-of-subtree))))))

(defun avy-org-parent-level (&optional all)
  "Go to any org heading one level above the current one.

By default, choices are limited to headings under common
subheading, but if called with a prefix argument, will be
buffer-global."
  (interactive "P")
  (let ((org-level (org-current-level)))
    (if (= org-level 1)
        (message "Already at top level.")
      (avy--generic-jump
       (format "^%s "
               (regexp-quote
                (make-string (- org-level 1) ?*)))
       nil
       'pre
       (unless (or all (= org-level 2))
         (save-excursion
           (outline-up-heading 2)
           (point)))
       (unless (or all (= org-level 2))
         (save-excursion
           (outline-up-heading 2)
           (org-end-of-subtree)))))))

(defun avy-org-child-level (&optional all)
  "Go to any org heading one level below the current one.

By default, choices are limited to headings under common
subheading, but if called with a prefix argument, will be
buffer-global."
  (interactive "P")
  (if (save-excursion (org-goto-first-child))
      (let ((org-level (org-current-level)))
        (avy--generic-jump
         (format "^%s "
                 (regexp-quote
                  (make-string (+ org-level 1) ?*)))
         nil
         'pre
         (unless all
           (save-excursion
             (ignore-errors
               (outline-up-heading 0))
             (point)))
         (unless all
           (save-excursion
             (ignore-errors
               (outline-up-heading 0))
             (org-end-of-subtree)))))
    (message "Heading has no children.")))

(defun avy-org-goto-level (&optional num)
  "Prompt for an org level to go to, defaulting to the current one."
  (interactive (list
                (read-number "Select heading level: " (org-current-level))))
  (avy--generic-jump
   (format "^%s " (regexp-quote (make-string num ?*)))
   nil
   'pre))

Jumping to an agenda item

(defun avy--org-agenda-cands ()
  (let (candidates point)
    (save-excursion
      (save-restriction
        (narrow-to-region (window-start) (window-end (selected-window) t))
        (setq point (goto-char (point-min)))
        (while (setq point (text-property-not-all point (window-end) 'org-marker nil))
          (push (cons point (selected-window)) candidates)
          (setq point (text-property-any point (window-end) 'org-marker nil)))))
    (nreverse candidates)))

(defun avy-org-agenda ()
  "Goto a visible item in an `org-mode-agenda' buffer."
  (interactive)
  (avy-action-goto (avy-with avy-org-agenda
                     (avy-process (avy--org-agenda-cands)))))

Jumping to a word start on the current line only

(defun avy-goto-word-crt-line ()
  "Jump to a word start on the current line only."
  (interactive)
  (avy-with avy-goto-word-0
    (avy-goto-word-0 nil (line-beginning-position) (line-end-position))))

;; optional evil integration example
(declare-function 'avy-goto-word-crt-line "avy")
(evil-define-avy-motion avy-goto-word-crt-line inclusive)

(define-key evil-motion-state-map (kbd "w") #'evil-avy-goto-word-crt-line)

Jump to a cell in an org-mode table

(defun avy-org-table-1-char ()
  "Avy navigation of cells in org-mode tables.  'SPC' can be used to jump to blank cells. "
  (interactive)
  ;; set some variables to limit candidates to the current table
  (let ((table-begin (save-excursion (goto-char (org-table-begin)) (previous-line) (point)))
        (table-end (save-excursion (goto-char (org-table-end)) (next-line) (point))))
  ;; jump to the desired cell and re-align
  (goto-char
   (avy--generic-jump (concat "|\\{1\\}[^-\n|]+" (char-to-string (read-char "char: " t))) t 'post table-begin table-end))
  (org-cycle)))