1 ;;; avy.el --- set-based completion -*- lexical-binding: t -*-
3 ;; Copyright (C) 2015 Free Software Foundation, Inc.
5 ;; Author: Oleh Krehel <ohwoeowho@gmail.com>
6 ;; URL: https://github.com/abo-abo/avy
8 ;; Package-Requires: ((emacs "24.1") (cl-lib "0.5"))
9 ;; Keywords: point, location
11 ;; This file is part of GNU Emacs.
13 ;; This file is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 3, or (at your option)
18 ;; This program is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; For a full copy of the GNU General Public License
24 ;; see <http://www.gnu.org/licenses/>.
28 ;; This package provides a generic completion method based on building
29 ;; a balanced decision tree with each candidate being a leaf. To
30 ;; traverse the tree from the root to a desired leaf, typically a
31 ;; sequence of `read-char' can be used.
33 ;; In order for `read-char' to make sense, the tree needs to be
34 ;; visualized appropriately, with a character at each branch node. So
35 ;; this completion method works only for things that you can see on
36 ;; your screen, all at once:
38 ;; * character positions
39 ;; * word or subword start positions
40 ;; * line beginning positions
44 ;; If you're familiar with the popular `ace-jump-mode' package, this
45 ;; package does all that and more, without the implementation
53 "Jump to things tree-style."
57 (defcustom avy-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)
58 "Default keys for jumping."
59 :type '(repeat :tag "Keys" character))
61 (defcustom avy-keys-alist nil
62 "Alist of avy-jump commands to `avy-keys' overriding the default `avy-keys'."
64 :key-type (choice :tag "Command"
66 (const avy-goto-char-2)
69 (const avy-goto-subword-0)
70 (const avy-goto-subword-1)
71 (const avy-goto-word-0)
72 (const avy-goto-word-1)
74 (const avy-copy-region)
75 (const avy-move-line))
76 :value-type (repeat :tag "Keys" character)))
78 (defcustom avy-style 'pre
79 "The default method of displaying the overlays.
80 Use `avy-styles-alist' to customize this per-command."
82 (const :tag "Pre" pre)
84 (const :tag "At Full" at-full)
85 (const :tag "Post" post)
86 (const :tag "De Bruijn" de-bruijn)))
88 (defcustom avy-styles-alist nil
89 "Alist of avy-jump commands to the style for each command.
90 If the commands isn't on the list, `avy-style' is used."
92 :key-type (choice :tag "Command"
94 (const avy-goto-char-2)
97 (const avy-goto-subword-0)
98 (const avy-goto-subword-1)
99 (const avy-goto-word-0)
100 (const avy-goto-word-1)
101 (const avy-copy-line)
102 (const avy-copy-region)
103 (const avy-move-line))
105 (const :tag "Pre" pre)
107 (const :tag "At Full" at-full)
108 (const :tag "Post" post))))
110 (defcustom avy-background nil
111 "When non-nil, a gray background will be added during the selection."
114 (defcustom avy-all-windows t
115 "Determine the list of windows to consider in search of candidates."
118 (const :tag "All Frames" all-frames)
119 (const :tag "This Frame" t)
120 (const :tag "This Window" nil)))
122 (defcustom avy-case-fold-search t
123 "Non-nil if searches should ignore case."
126 (defcustom avy-word-punc-regexp "[!-/:-@[-`{-~]"
127 "Regexp of punctuation chars that count as word starts for `avy-goto-word-1.
128 When nil, punctuation chars will not be matched.
130 \"[!-/:-@[-`{-~]\" will match all printable punctuation chars."
133 (defface avy-lead-face-0
134 '((t (:foreground "white" :background "#4f57f9")))
135 "Face used for first non-terminating leading chars.")
137 (defface avy-lead-face-1
138 '((t (:foreground "white" :background "gray")))
139 "Face used for matched leading chars.")
141 (defface avy-lead-face
142 '((t (:foreground "white" :background "#e52b50")))
143 "Face used for the leading chars.")
145 (defface avy-background-face
146 '((t (:foreground "gray40")))
147 "Face for whole window background during selection.")
151 (defmacro avy-multipop (lst n)
152 "Remove LST's first N elements and return them."
153 `(if (<= (length ,lst) ,n)
158 (nthcdr (1- ,n) (prog1 ,lst (setq ,lst (nthcdr ,n ,lst))))
161 (defun avy--de-bruijn (keys n)
162 "De Bruijn sequence for alphabet KEYS and subsequences of length N."
163 (let* ((k (length keys))
164 (a (make-list (* n k) 0))
166 (cl-labels ((db (T p)
171 (cl-subseq a 1 (1+ p)))))
172 (setf (nth T a) (nth (- T p) a))
174 (cl-loop for j from (1+ (nth (- T p) a)) to (1- k) do
182 (defun avy--path-alist-1 (lst seq-len keys)
183 "Build a De Bruin sequence from LST.
184 SEQ-LEN is how many elements of KEYS it takes to identify a match."
185 (let ((db-seq (avy--de-bruijn keys seq-len))
186 prev-pos prev-seq prev-win path-alist)
187 ;; The De Bruijn seq is cyclic, so append the seq-len - 1 first chars to
189 (setq db-seq (nconc db-seq (cl-subseq db-seq 0 (1- seq-len))))
190 (cl-labels ((subseq-and-pop ()
191 (when (nth (1- seq-len) db-seq)
192 (prog1 (cl-subseq db-seq 0 seq-len)
195 (let* ((cur (car lst))
197 ;; ace-window has matches of the form (pos . wnd)
198 ((integerp (car cur)) (car cur))
199 ;; avy-jump have form ((start . end) . wnd)
200 ((consp (car cur)) (caar cur))
201 (t (error "Unexpected match representation: %s" cur))))
204 (let ((diff (if (eq win prev-win)
207 (when (and (> diff 0) (< diff seq-len))
208 (while (and (nth (1- seq-len) db-seq)
211 (cl-subseq prev-seq diff)
212 (cl-subseq db-seq 0 seq-len)))))
219 (push (cons path (car lst)) path-alist)
224 (nreverse path-alist)))
226 (defun avy--group-by (fn seq)
227 "Apply FN to each element of SEQ.
228 Separate the elements of SEQ into an alist using the results as
229 keys. Keys are compared using `equal'."
232 (let* ((el (pop seq))
234 (entry (assoc r alist)))
236 (setcdr entry (cons el (cdr entry)))
237 (push (list r el) alist))))
240 (defun avy--path-alist-to-tree (p-alist)
241 "Convert P-ALIST to the format of `avy-tree'."
242 (if (> (length (caar p-alist)) 1)
244 (setcdr x (avy--path-alist-to-tree
246 (cons (cdar c) (cdr c)))
249 (avy--group-by #'caar p-alist))
252 (cons 'leaf (cdr x))))
255 (defun avy-tree-de-bruijn (lst keys)
256 "Coerse LST into a tree.
257 The degree of the tree is the length of KEYS.
258 KEYS are placed on the internal nodes according to De Bruijn sequences.
259 LST elements should be of the form ((BEG . END) WND)."
260 ;; In theory, the De Bruijn sequence B(k,n) has k^n subsequences of length n
261 ;; (the path length) usable as paths, thus that's the lower bound. Due to
262 ;; partially overlapping matches, not all subsequences may be usable, so it's
263 ;; possible that the path-len must be incremented, e.g., if we're matching
264 ;; for x and a buffer contains xaxbxcx only every second subsequence is
265 ;; usable for the four matches.
266 (let* ((path-len (ceiling (log (length lst) (length keys))))
267 (path-alist (avy--path-alist-1 lst path-len keys)))
268 (while (not path-alist)
270 (setq path-alist (avy--path-alist-1 lst path-len keys)))
271 (avy--path-alist-to-tree path-alist)))
273 (defun avy-tree (lst keys)
274 "Coerce LST into a balanced tree.
275 The degree of the tree is the length of KEYS.
276 KEYS are placed appropriately on internal nodes."
277 (let ((len (length keys)))
280 (let ((ln (length ls)))
283 (mapcar (lambda (x) (cons 'leaf x)) ls))
284 (let ((ks (copy-sequence keys))
286 (dolist (s (avy-subdiv ln len))
289 (cons 'leaf (pop ls))
290 (rd (avy-multipop ls s))))
295 (defun avy-subdiv (n b)
296 "Distribute N in B terms in a balanced way."
297 (let* ((p (1- (floor (+ (log n b) 1e-6))))
301 (n2 (/ delta (- x2 x1)))
306 (- n (* n1 x1) (* n2 x2)))
309 (defun avy-traverse (tree walker &optional recur-key)
310 "Traverse TREE generated by `avy-tree'.
311 WALKER is a function that takes KEYS and LEAF.
313 RECUR-KEY is used in recursion.
315 LEAF is a member of LST argument of `avy-tree'.
317 KEYS is the path from the root of `avy-tree' to LEAF."
319 (let ((key (cons (car br) recur-key)))
320 (if (eq (cadr br) 'leaf)
321 (funcall walker key (cddr br))
322 (avy-traverse (cdr br) walker key)))))
324 (defun avy-handler-default (char)
325 "The default hander for a bad CHAR."
326 (signal 'user-error (list "No such candidate" char))
329 (defvar avy-handler-function 'avy-handler-default
330 "A function to call for a bad `read-char' in `avy-read'.")
332 (defvar avy-current-path ""
333 "Store the current incomplete path during `avy-read'.")
335 (defun avy-read (tree display-fn cleanup-fn)
336 "Select a leaf from TREE using consecutive `read-char'.
338 DISPLAY-FN should take CHAR and LEAF and signify that LEAFs
339 associated with CHAR will be selected if CHAR is pressed. This is
340 commonly done by adding a CHAR overlay at LEAF position.
342 CLEANUP-FN should take no arguments and remove the effects of
343 multiple DISPLAY-FN invokations."
345 (setq avy-current-path "")
347 (let ((avy--leafs nil))
350 (push (cons path leaf) avy--leafs)))
351 (dolist (x avy--leafs)
352 (funcall display-fn (car x) (cdr x))))
353 (let ((char (read-char))
356 (if (setq branch (assoc char tree))
357 (if (eq (car (setq tree (cdr branch))) 'leaf)
358 (throw 'done (cdr tree))
359 (setq avy-current-path
360 (concat avy-current-path (string char))))
361 (funcall avy-handler-function char))))))
364 (defun avy-window-list ()
365 "Return a list of windows depending on `avy-all-windows'."
366 (cond ((eq avy-all-windows 'all-frames)
367 (cl-mapcan #'window-list (frame-list)))
369 ((eq avy-all-windows t)
372 ((null avy-all-windows)
373 (list (selected-window)))
376 (error "Unrecognized option: %S" avy-all-windows))))
378 (defmacro avy-dowindows (flip &rest body)
379 "Depending on FLIP and `avy-all-windows' run BODY in each or selected window."
382 `(let ((avy-all-windows (if ,flip
383 (not avy-all-windows)
385 (dolist (wnd (avy-window-list))
386 (with-selected-window wnd
387 (unless (memq major-mode '(image-mode doc-view-mode))
390 (defmacro avy--with-avy-keys (command &rest body)
391 "Set `avy-keys' according to COMMAND and execute BODY."
394 `(let ((avy-keys (or (cdr (assq ',command avy-keys-alist))
396 (avy-style (or (cdr (assq ',command avy-styles-alist))
403 POS is either a position or (BEG . END)."
405 (message "zero candidates"))
407 ;; ignore exit from `avy-handler-function'
411 (select-window (cdr x))
415 (unless (= pt (point)) (push-mark))
418 (defun avy--process (candidates overlay-fn)
419 "Select one of CANDIDATES using `avy-read'.
420 Use OVERLAY-FN to visualize the decision overlay."
422 (cl-case (length candidates)
428 (avy--make-backgrounds
430 (avy-read (if (eq avy-style 'de-bruijn)
431 (avy-tree-de-bruijn candidates avy-keys)
432 (avy-tree candidates avy-keys))
434 #'avy--remove-leading-chars)))
437 (defvar avy--overlays-back nil
438 "Hold overlays for when `avy-background' is t.")
440 (defun avy--make-backgrounds (wnd-list)
441 "Create a dim background overlay for each window on WND-LIST."
443 (setq avy--overlays-back
445 (let ((ol (make-overlay
449 (overlay-put ol 'face 'avy-background-face)
450 (overlay-put ol 'window w)
456 (mapc #'delete-overlay avy--overlays-back)
457 (setq avy--overlays-back nil)
458 (avy--remove-leading-chars))
460 (defun avy--regex-candidates (regex &optional beg end pred group)
461 "Return all elements that match REGEX.
462 Each element of the list is ((BEG . END) . WND)
463 When PRED is non-nil, it's a filter for matching point positions.
464 When GROUP is non-nil, (BEG . END) should delimit that regex group."
465 (setq group (or group 0))
466 (let ((case-fold-search avy-case-fold-search)
469 (let ((we (or end (window-end (selected-window) t))))
471 (goto-char (or beg (window-start)))
472 (while (re-search-forward regex we t)
473 (unless (get-char-property (point) 'invisible)
474 (when (or (null pred)
476 (push (cons (cons (match-beginning group)
478 wnd) candidates)))))))
479 (nreverse candidates)))
481 (defvar avy--overlay-offset 0
482 "The offset to apply in `avy--overlay'.")
484 (defvar avy--overlays-lead nil
485 "Hold overlays for leading chars.")
487 (defun avy--remove-leading-chars ()
488 "Remove leading char overlays."
489 (mapc #'delete-overlay avy--overlays-lead)
490 (setq avy--overlays-lead nil))
492 (defun avy--overlay (str pt wnd)
493 "Create an overlay with STR at PT in WND."
494 (when (<= (1+ pt) (with-selected-window wnd (point-max)))
495 (let* ((pt (+ pt avy--overlay-offset))
496 (ol (make-overlay pt (1+ pt) (window-buffer wnd)))
497 (old-str (with-selected-window wnd
498 (buffer-substring pt (1+ pt)))))
500 (setq old-str (propertize
501 old-str 'face 'avy-background-face)))
502 (overlay-put ol 'window wnd)
503 (overlay-put ol 'display (concat str old-str))
504 (push ol avy--overlays-lead))))
506 (defcustom avy-highlight-first nil
507 "When non-nil highlight the first decision char with `avy-lead-face-0'.
508 Do this even when the char is terminating."
511 (defun avy--overlay-pre (path leaf)
512 "Create an overlay with PATH at LEAF.
513 PATH is a list of keys from tree root to LEAF.
514 LEAF is normally ((BEG . END) . WND)."
515 (let ((str (propertize (apply #'string (reverse path))
516 'face 'avy-lead-face)))
517 (when (or avy-highlight-first (> (length str) 1))
518 (set-text-properties 0 1 '(face avy-lead-face-0) str))
520 (propertize avy-current-path
521 'face 'avy-lead-face-1)
525 (cond ((numberp leaf)
533 (selected-window)))))
535 (defun avy--overlay-at (path leaf)
536 "Create an overlay with PATH at LEAF.
537 PATH is a list of keys from tree root to LEAF.
538 LEAF is normally ((BEG . END) . WND)."
539 (let ((str (propertize
540 (string (car (last path)))
541 'face 'avy-lead-face))
542 (pt (+ (if (consp (car leaf))
545 avy--overlay-offset))
547 (let ((ol (make-overlay pt (1+ pt)
548 (window-buffer wnd)))
549 (old-str (with-selected-window wnd
550 (buffer-substring pt (1+ pt)))))
552 (setq old-str (propertize
553 old-str 'face 'avy-background-face)))
554 (overlay-put ol 'window wnd)
555 (overlay-put ol 'display (if (string= old-str "\n")
558 (push ol avy--overlays-lead))))
560 (defun avy--overlay-at-full (path leaf)
561 "Create an overlay with PATH at LEAF.
562 PATH is a list of keys from tree root to LEAF.
563 LEAF is normally ((BEG . END) . WND)."
564 (let* ((str (propertize
565 (apply #'string (reverse path))
566 'face 'avy-lead-face))
568 (beg (if (consp (car leaf))
572 (when (or avy-highlight-first (> (length str) 1))
573 (set-text-properties 0 1 '(face avy-lead-face-0) str))
574 (with-selected-window wnd
577 (when (cl-some (lambda (o)
578 (and (eq (overlay-get o 'category) 'avy)
579 (eq (overlay-get o 'window) wnd)))
580 (overlays-in (point) (min (+ (point) len)
581 (line-end-position))))
582 (setq str (substring str 0 1))
584 (let ((other-ov (cl-find-if
586 (and (eq (overlay-get o 'category) 'avy)
587 (eq (overlay-start o) beg)
588 (not (eq (overlay-get o 'window) wnd))))
589 (overlays-in (point) (min (+ (point) len)
590 (line-end-position))))))
592 (> (overlay-end other-ov)
594 (setq str (concat str (buffer-substring
596 (overlay-end other-ov))))
597 (setq len (- (overlay-end other-ov)
599 (let* ((end (if (= beg (line-end-position))
602 (if (eq (char-after) ?\t)
605 (line-end-position))))
609 (old-str (buffer-substring beg (1+ beg))))
611 (setq old-str (propertize
612 old-str 'face 'avy-background-face)))
613 (overlay-put ol 'window wnd)
614 (overlay-put ol 'category 'avy)
615 (overlay-put ol 'display
616 (cond ((string= old-str "\n")
618 ((string= old-str "\t")
619 (concat str (make-string (- tab-width len) ?\ )))
622 (push ol avy--overlays-lead))))))
624 (defun avy--overlay-post (path leaf)
625 "Create an overlay with PATH at LEAF.
626 PATH is a list of keys from tree root to LEAF.
627 LEAF is normally ((BEG . END) . WND)."
628 (let ((str (propertize (apply #'string (reverse path))
629 'face 'avy-lead-face)))
630 (when (or avy-highlight-first (> (length str) 1))
631 (set-text-properties 0 1 '(face avy-lead-face-0) str))
633 (propertize avy-current-path
634 'face 'avy-lead-face-1)
638 (cond ((numberp leaf)
646 (selected-window)))))
648 (defun avy--style-fn (style)
649 "Transform STYLE symbol to a style function."
651 (pre #'avy--overlay-pre)
652 (at #'avy--overlay-at)
653 (at-full 'avy--overlay-at-full)
654 (post #'avy--overlay-post)
655 (de-bruijn #'avy--overlay-at-full)
656 (t (error "Unexpected style %S" style))))
658 (defun avy--generic-jump (regex window-flip style)
660 When WINDOW-FLIP is non-nil, do the opposite of `avy-all-windows'.
661 STYLE determines the leading char overlay style."
662 (let ((avy-all-windows
664 (not avy-all-windows)
668 (avy--regex-candidates regex)
669 (avy--style-fn style)))))
673 (defun avy-goto-char (char &optional arg)
674 "Jump to the currently visible CHAR.
675 The window scope is determined by `avy-all-windows' (ARG negates it)."
676 (interactive (list (read-char "char: ")
678 (avy--with-avy-keys avy-goto-char
682 (regexp-quote (string char)))
687 (defun avy-goto-char-in-line (char &optional arg)
688 "Jump to the currently visible CHAR in the current line.
689 The window scope is determined by `avy-all-windows' (ARG negates it)."
690 (interactive (list (read-char "char: ")
692 (let ((avy-all-windows
694 (not avy-all-windows)
696 (avy--with-avy-keys avy-goto-char
700 (narrow-to-region (line-beginning-position)
702 (avy--regex-candidates (string char)))
703 (avy--style-fn avy-style))))))
706 (defun avy-goto-char-2 (char1 char2 &optional arg)
707 "Jump to the currently visible CHAR1 followed by CHAR2.
708 The window scope is determined by `avy-all-windows' (ARG negates it)."
709 (interactive (list (read-char "char 1: ")
710 (read-char "char 2: ")
712 (avy--with-avy-keys avy-goto-char-2
714 (regexp-quote (string char1 char2))
719 (defun avy-isearch ()
720 "Jump to one of the current isearch candidates."
722 (avy--with-avy-keys avy-isearch
724 (avy--regex-candidates isearch-string))
727 (avy--process candidates #'avy--overlay-post)))
729 (avy--goto candidate))))
732 (defun avy-goto-word-0 (arg)
733 "Jump to a word start.
734 The window scope is determined by `avy-all-windows' (ARG negates it)."
736 (avy--with-avy-keys avy-goto-word-0
737 (avy--generic-jump "\\b\\sw" arg avy-style)))
740 (defun avy-goto-word-1 (char &optional arg)
741 "Jump to the currently visible CHAR at a word start.
742 The window scope is determined by `avy-all-windows' (ARG negates it)."
743 (interactive (list (read-char "char: ")
745 (avy--with-avy-keys avy-goto-word-1
746 (let* ((str (string char))
747 (regex (cond ((string= str ".")
749 ((and avy-word-punc-regexp
750 (string-match avy-word-punc-regexp str))
756 (avy--generic-jump regex arg avy-style))))
758 (declare-function subword-backward "subword")
761 (defun avy-goto-subword-0 (&optional arg predicate)
762 "Jump to a word or subword start.
764 The window scope is determined by `avy-all-windows' (ARG negates it).
766 When PREDICATE is non-nil it's a function of zero parameters that
770 (avy--with-avy-keys avy-goto-subword-0
771 (let ((case-fold-search nil)
774 (let ((ws (window-start))
777 (goto-char (window-end (selected-window) t))
779 (while (> (point) ws)
780 (when (or (null predicate)
781 (and predicate (funcall predicate)))
782 (push (cons (point) (selected-window)) window-cands))
784 (setq candidates (nconc candidates window-cands))))
786 (avy--process candidates (avy--style-fn avy-style))))))
789 (defun avy-goto-subword-1 (char arg)
790 "Jump to the currently visible CHAR at a subword start.
791 The window scope is determined by `avy-all-windows' (ARG negates it).
792 The case of CHAR is ignored."
793 (interactive (list (read-char "char: ")
795 (avy--with-avy-keys avy-goto-subword-1
796 (let ((char (downcase char)))
798 arg (lambda () (eq (downcase (char-after)) char))))))
800 (defun avy-goto-word-or-subword-1 ()
801 "Forward to `avy-goto-subword-1' or `avy-goto-word-1'.
802 Which one depends on variable `subword-mode'."
804 (if (bound-and-true-p subword-mode)
805 (call-interactively #'avy-goto-subword-1)
806 (call-interactively #'avy-goto-word-1)))
808 (defun avy--line (&optional arg)
810 The window scope is determined by `avy-all-windows' (ARG negates it)."
811 (let ((avy-background nil)
814 (let ((ws (window-start)))
817 (narrow-to-region ws (window-end (selected-window) t))
818 (goto-char (point-min))
819 (while (< (point) (point-max))
820 (unless (get-char-property
821 (max (1- (point)) ws) 'invisible)
823 (if (eq avy-style 'post)
825 (line-beginning-position))
826 (selected-window)) candidates))
827 (forward-line 1))))))
828 (avy--process (nreverse candidates) (avy--style-fn avy-style))))
831 (defun avy-goto-line (&optional arg)
832 "Jump to a line start in current buffer.
833 The window scope is determined by `avy-all-windows' (ARG negates it)."
835 (avy--with-avy-keys avy-goto-line
836 (let ((avy-handler-function
840 (avy-handler-default char)
841 (let ((line (read-from-minibuffer
842 "Goto line: " (string char))))
844 (goto-char (point-min))
845 (forward-line (1- (string-to-number line)))
846 (throw 'done 'exit)))))))
847 (avy--goto (avy--line arg)))))
850 (defun avy-copy-line (arg)
851 "Copy a selected line above the current line.
852 ARG lines can be used."
854 (avy--with-avy-keys avy-copy-line
855 (let ((start (car (avy--line))))
856 (move-beginning-of-line nil)
859 (buffer-substring-no-properties
863 (move-end-of-line arg)
868 (defun avy-move-line (arg)
869 "Move a selected line above the current line.
870 ARG lines can be used."
872 (avy--with-avy-keys avy-move-line
873 (let ((start (car (avy--line))))
874 (move-beginning-of-line nil)
878 (kill-whole-line arg))
880 (current-kill 0))))))
883 (defun avy-copy-region ()
884 "Select two lines and copy the text between them here."
886 (avy--with-avy-keys avy-copy-region
887 (let ((beg (car (avy--line)))
888 (end (car (avy--line)))
889 (pad (if (bolp) "" "\n")))
890 (move-beginning-of-line nil)
893 (buffer-substring-no-properties
897 (line-end-position)))
901 (defun avy-setup-default ()
902 "Setup the default shortcuts."
903 (eval-after-load "isearch"
904 '(define-key isearch-mode-map (kbd "C-'") 'avy-isearch)))
906 (defcustom avy-timeout-seconds 0.5
907 "How many seconds to wait for the second char.")
910 (defun avy-goto-char-timer (&optional arg)
911 "Read one or two consecutive chars and jump to the first one.
912 The window scope is determined by `avy-all-windows' (ARG negates it)."
914 (let ((c1 (read-char "char 1: "))
915 (c2 (read-char "char 2: " nil avy-timeout-seconds)))
924 (define-obsolete-variable-alias
925 'avy-goto-char-style 'avy-style "0.1.0"
926 "Use `avy-style' and `avy-styles-alist' instead.")
927 (define-obsolete-variable-alias
928 'avy-goto-word-style 'avy-style "0.1.0"
929 "Use `avy-style' and `avy-styles-alist' instead.")
930 (define-obsolete-variable-alias 'avi-keys 'avy-keys "0.1.0")
931 (define-obsolete-variable-alias 'avi-background 'avy-background "0.1.0")
932 (define-obsolete-variable-alias 'avi-word-punc-regexp 'avy-word-punc-regexp "0.1.0")
933 (define-obsolete-face-alias 'avi-lead-face 'avy-lead-face "0.1.0")
934 (define-obsolete-function-alias 'avi--goto 'avy--goto "0.1.0")
935 (define-obsolete-function-alias 'avi--process 'avy--process "0.1.0")
936 (define-obsolete-variable-alias 'avi-all-windows 'avy-all-windows "0.1.0")
937 (define-obsolete-function-alias 'avi--overlay-pre 'avy--overlay-pre "0.1.0")
938 (define-obsolete-function-alias 'avi--overlay-at 'avy--overlay-at "0.1.0")
939 (define-obsolete-function-alias 'avi--overlay-post 'avy--overlay-post "0.1.0")
940 (define-obsolete-function-alias 'avi-goto-char 'avy-goto-char "0.1.0")
941 (define-obsolete-function-alias 'avi-goto-char-2 'avy-goto-char-2 "0.1.0")
942 (define-obsolete-function-alias 'avi-isearch 'avy-isearch "0.1.0")
943 (define-obsolete-function-alias 'avi-goto-word-0 'avy-goto-word-0 "0.1.0")
944 (define-obsolete-function-alias 'avi-goto-subword-0 'avy-goto-subword-0 "0.1.0")
945 (define-obsolete-function-alias 'avi-goto-word-1 'avy-goto-word-1 "0.1.0")
946 (define-obsolete-function-alias 'avi-goto-line 'avy-goto-line "0.1.0")
947 (define-obsolete-function-alias 'avi-copy-line 'avy-copy-line "0.1.0")
948 (define-obsolete-function-alias 'avi-move-line 'avy-move-line "0.1.0")
949 (define-obsolete-function-alias 'avi-copy-region 'avy-copy-region "0.1.0")
950 (define-obsolete-function-alias 'avi--regex-candidates 'avy--regex-candidates "0.1.0")