-;;; avy.el --- set-based completion -*- lexical-binding: t -*-
+;;; avy.el --- tree-based completion -*- lexical-binding: t -*-
;; Copyright (C) 2015 Free Software Foundation, Inc.
;; possible that the path-len must be incremented, e.g., if we're matching
;; for x and a buffer contains xaxbxcx only every second subsequence is
;; usable for the four matches.
- (let* ((path-len (ceiling (log (length lst) (length keys))))
- (alist (avy--path-alist-1 lst path-len keys)))
- (while (not alist)
- (cl-incf path-len)
- (setq alist (avy--path-alist-1 lst path-len keys)))
- (let* ((len (length (caar alist)))
- (i 0))
- (setq avy-current-path "")
- (while (< i len)
- (dolist (x (reverse alist))
- (avy--overlay-at-full (reverse (car x)) (cdr x)))
- (let ((char (funcall avy-translate-char-function (read-key))))
- (avy--remove-leading-chars)
- (setq alist
- (delq nil
- (mapcar (lambda (x)
- (when (eq (caar x) char)
- (cons (cdr (car x)) (cdr x))))
- alist)))
- (setq avy-current-path
- (concat avy-current-path (string (avy--key-to-char char))))
- (cl-incf i)
- (unless alist
- (funcall avy-handler-function char))))
- (cdar alist))))
+ (catch 'done
+ (let* ((path-len (ceiling (log (length lst) (length keys))))
+ (alist (avy--path-alist-1 lst path-len keys)))
+ (while (not alist)
+ (cl-incf path-len)
+ (setq alist (avy--path-alist-1 lst path-len keys)))
+ (let* ((len (length (caar alist)))
+ (i 0))
+ (setq avy-current-path "")
+ (while (< i len)
+ (dolist (x (reverse alist))
+ (avy--overlay-at-full (reverse (car x)) (cdr x)))
+ (let ((char (funcall avy-translate-char-function (read-key))))
+ (avy--remove-leading-chars)
+ (setq alist
+ (delq nil
+ (mapcar (lambda (x)
+ (when (eq (caar x) char)
+ (cons (cdr (car x)) (cdr x))))
+ alist)))
+ (setq avy-current-path
+ (concat avy-current-path (string (avy--key-to-char char))))
+ (cl-incf i)
+ (unless alist
+ (funcall avy-handler-function char))))
+ (cdar alist)))))
;;** Rest
(defun avy-window-list ()
(t
(error "Unrecognized option: %S" avy-all-windows))))
+(defcustom avy-all-windows-alt t
+ "The alternative `avy-all-windows' for use with \\[universal-argument]."
+ :type '(choice
+ (const :tag "All windows on the current frame" t)
+ (const :tag "All windows on all frames" all-frames)))
+
(defmacro avy-dowindows (flip &rest body)
"Depending on FLIP and `avy-all-windows' run BODY in each or selected window."
(declare (indent 1)
(debug (form body)))
`(let ((avy-all-windows (if ,flip
- (not avy-all-windows)
+ avy-all-windows-alt
avy-all-windows)))
(dolist (wnd (avy-window-list))
(with-selected-window wnd
(defun avy--process (candidates overlay-fn)
"Select one of CANDIDATES using `avy-read'.
Use OVERLAY-FN to visualize the decision overlay."
+ (unless (and (consp (car candidates))
+ (windowp (cdar candidates)))
+ (setq candidates
+ (mapcar (lambda (x) (cons x (selected-window)))
+ candidates)))
(let ((len (length candidates))
(cands (copy-sequence candidates))
res)
(defun avy--find-visible-regions (rbeg rend)
"Return a list of all visible regions between RBEG and REND."
- (let (visibles beg)
- (save-excursion
- (save-restriction
- (narrow-to-region rbeg rend)
- (setq beg (goto-char (point-min)))
- (while (not (= (point) (point-max)))
- (goto-char (avy--next-invisible-point))
- (push (cons beg (point)) visibles)
- (setq beg (goto-char (avy--next-visible-point))))
- (nreverse visibles)))))
+ (setq rbeg (max rbeg (point-min)))
+ (setq rend (min rend (point-max)))
+ (when (< rbeg rend)
+ (let (visibles beg)
+ (save-excursion
+ (save-restriction
+ (narrow-to-region rbeg rend)
+ (setq beg (goto-char (point-min)))
+ (while (not (= (point) (point-max)))
+ (goto-char (avy--next-invisible-point))
+ (push (cons beg (point)) visibles)
+ (setq beg (goto-char (avy--next-visible-point))))
+ (nreverse visibles))))))
(defun avy--regex-candidates (regex &optional beg end pred group)
"Return all elements that match REGEX.
When GROUP is non-nil, (BEG . END) should delimit that regex group."
(setq group (or group 0))
(let ((case-fold-search (or avy-case-fold-search
- (not (string= regex (upcase regex)))))
+ (string= regex (downcase regex))))
candidates)
- (avy-dowindows nil
+ (avy-dowindows current-prefix-arg
(dolist (pair (avy--find-visible-regions
(or beg (window-start))
(or end (window-end (selected-window) t))))
(save-excursion
(goto-char (car pair))
(while (re-search-forward regex (cdr pair) t)
- (unless (get-char-property (point) 'invisible)
+ (unless (get-char-property (1- (point)) 'invisible)
(when (or (null pred)
(funcall pred))
(push (cons (cons (match-beginning group)
(mapc #'delete-overlay avy--overlays-lead)
(setq avy--overlays-lead nil))
-(defun avy--overlay (str pt wnd)
- "Create an overlay with STR at PT in WND."
- (when (<= (1+ pt) (with-selected-window wnd (point-max)))
- (let* ((pt (+ pt avy--overlay-offset))
- (ol (make-overlay pt (1+ pt) (window-buffer wnd)))
- (old-str (with-selected-window wnd
- (buffer-substring pt (1+ pt)))))
- (when avy-background
- (setq old-str (propertize
- old-str 'face 'avy-background-face)))
- (overlay-put ol 'window wnd)
- (overlay-put ol 'display (concat str old-str))
- (push ol avy--overlays-lead))))
+(defun avy--old-str (pt wnd)
+ "Return a one-char string at PT in WND."
+ (let ((old-str (with-selected-window wnd
+ (buffer-substring pt (1+ pt)))))
+ (if avy-background
+ (propertize old-str 'face 'avy-background-face)
+ old-str)))
+
+(defun avy--overlay (str beg end wnd &optional compose-fn)
+ "Create an overlay with STR from BEG to END in WND.
+COMPOSE-FN is a lambda that concatenates the old string at BEG with STR."
+ (let ((eob (with-selected-window wnd (point-max))))
+ (when (<= beg eob)
+ (let* ((beg (+ beg avy--overlay-offset))
+ (ol (make-overlay beg (or end (1+ beg)) (window-buffer wnd)))
+ (old-str (if (eq beg eob) "" (avy--old-str beg wnd)))
+ (os-line-prefix (get-text-property 0 'line-prefix old-str))
+ (os-wrap-prefix (get-text-property 0 'wrap-prefix old-str))
+ other-ol)
+ (when os-line-prefix
+ (add-text-properties 0 1 `(line-prefix ,os-line-prefix) str))
+ (when os-wrap-prefix
+ (add-text-properties 0 1 `(wrap-prefix ,os-wrap-prefix) str))
+ (when (setq other-ol (cl-find-if
+ (lambda (o) (overlay-get o 'goto-address))
+ (overlays-at beg)))
+ (add-text-properties
+ 0 (length old-str)
+ `(face ,(overlay-get other-ol 'face)) old-str))
+ (overlay-put ol 'window wnd)
+ (overlay-put ol 'category 'avy)
+ (overlay-put ol (if (eq beg eob)
+ 'after-string
+ 'display)
+ (funcall
+ (or compose-fn #'concat)
+ str old-str))
+ (push ol avy--overlays-lead)))))
(defcustom avy-highlight-first nil
"When non-nil highlight the first decision char with `avy-lead-face-0'.
(or (cdr (assoc c avy-key-to-char-alist))
(error "Unknown key %s" c))))
+(defun avy-candidate-beg (leaf)
+ "Return the start position for LEAF."
+ (cond ((numberp leaf)
+ leaf)
+ ((consp (car leaf))
+ (caar leaf))
+ (t
+ (car leaf))))
+
+(defun avy-candidate-end (leaf)
+ "Return the end position for LEAF."
+ (cond ((numberp leaf)
+ leaf)
+ ((consp (car leaf))
+ (cdar leaf))
+ (t
+ (car leaf))))
+
+(defun avy-candidate-wnd (leaf)
+ "Return the window for LEAF."
+ (if (consp leaf)
+ (cdr leaf)
+ (selected-window)))
+
(defun avy--overlay-pre (path leaf)
"Create an overlay with PATH at LEAF.
PATH is a list of keys from tree root to LEAF.
str))
(avy--overlay
str
- (cond ((numberp leaf)
- leaf)
- ((consp (car leaf))
- (caar leaf))
- (t
- (car leaf)))
- (if (consp leaf)
- (cdr leaf)
- (selected-window)))))
+ (avy-candidate-beg leaf) nil
+ (avy-candidate-wnd leaf))))
(defun avy--overlay-at (path leaf)
"Create an overlay with PATH at LEAF.
(let* ((path (mapcar #'avy--key-to-char path))
(str (propertize
(string (car (last path)))
- 'face 'avy-lead-face))
- (pt (+ (if (consp (car leaf))
- (caar leaf)
- (car leaf))
- avy--overlay-offset))
- (wnd (cdr leaf))
- (ol (make-overlay pt (1+ pt)
- (window-buffer wnd)))
- (old-str (with-selected-window wnd
- (buffer-substring pt (1+ pt)))))
- (when avy-background
- (setq old-str (propertize
- old-str 'face 'avy-background-face)))
- (overlay-put ol 'window wnd)
- (overlay-put ol 'display (if (string= old-str "\n")
- (concat str "\n")
- ;; add padding for wide-width character
- (if (eq (string-width old-str) 2)
- (concat str " ")
- str)))
- (push ol avy--overlays-lead)))
+ 'face 'avy-lead-face)))
+ (avy--overlay
+ str
+ (avy-candidate-beg leaf) nil
+ (avy-candidate-wnd leaf)
+ (lambda (str old-str)
+ (cond ((string= old-str "\n")
+ (concat str "\n"))
+ ;; add padding for wide-width character
+ ((eq (string-width old-str) 2)
+ (concat str " "))
+ (t
+ str))))))
(defun avy--overlay-at-full (path leaf)
"Create an overlay with PATH at LEAF.
(apply #'string (reverse path))
'face 'avy-lead-face))
(len (length path))
- (beg (if (consp (car leaf))
- (caar leaf)
- (car leaf)))
+ (beg (avy-candidate-beg leaf))
(wnd (cdr leaf))
- oov)
+ end)
(dotimes (i len)
(set-text-properties (- len i 1) (- len i)
`(face ,(nth i avy-lead-faces))
(with-selected-window wnd
(save-excursion
(goto-char beg)
- (when (setq oov
- (delq nil
- (mapcar
- (lambda (o)
- (and (eq (overlay-get o 'category) 'avy)
- (eq (overlay-get o 'window) wnd)
- (overlay-start o)))
- (overlays-in (point) (min (+ (point) len)
- (line-end-position))))))
- (setq len (- (apply #'min oov) beg))
- (setq str (substring str 0 len)))
- (let ((other-ov (cl-find-if
- (lambda (o)
- (and (eq (overlay-get o 'category) 'avy)
- (eq (overlay-start o) beg)
- (not (eq (overlay-get o 'window) wnd))))
- (overlays-in (point) (min (+ (point) len)
- (line-end-position))))))
- (when (and other-ov
- (> (overlay-end other-ov)
- (+ beg len)))
- (setq str (concat str (buffer-substring
- (+ beg len)
- (overlay-end other-ov))))
- (setq len (- (overlay-end other-ov)
- beg))))
- (let* ((end (if (= beg (line-end-position))
+ (let* ((lep (if (bound-and-true-p visual-line-mode)
+ (save-excursion
+ (end-of-visual-line)
+ (point))
+ (line-end-position)))
+ (len-and-str (avy--update-offset-and-str len str lep)))
+ (setq len (car len-and-str))
+ (setq str (cdr len-and-str))
+ (setq end (if (= beg lep)
(1+ beg)
(min (+ beg
(if (eq (char-after) ?\t)
1
len))
- (line-end-position))))
- (ol (make-overlay
- beg end
- (current-buffer)))
- (old-str (buffer-substring beg (1+ beg))))
- (when avy-background
- (setq old-str (propertize
- old-str 'face 'avy-background-face)))
- (overlay-put ol 'window wnd)
- (overlay-put ol 'category 'avy)
- (overlay-put ol 'display
- (cond ((string= old-str "\n")
- (concat str "\n"))
- ((string= old-str "\t")
- (concat str (make-string (max (- tab-width len) 0) ?\ )))
- (t
- ;; add padding for wide-width character
- (if (eq (string-width old-str) 2)
- (concat str " ")
- str))))
- (push ol avy--overlays-lead))))))
+ lep)))
+ (when (and (bound-and-true-p visual-line-mode)
+ (> len (- end beg))
+ (not (eq lep beg)))
+ (setq len (- end beg))
+ (let ((old-str (apply #'string (reverse path))))
+ (setq str
+ (substring
+ (propertize
+ old-str
+ 'face
+ (if (= (length old-str) 1)
+ 'avy-lead-face
+ 'avy-lead-face-0))
+ 0 len)))))))
+ (avy--overlay
+ str beg end wnd
+ (lambda (str old-str)
+ (cond ((string= old-str "\n")
+ (concat str "\n"))
+ ((string= old-str "\t")
+ (concat str (make-string (max (- tab-width len) 0) ?\ )))
+ (t
+ ;; add padding for wide-width character
+ (if (eq (string-width old-str) 2)
+ (concat str " ")
+ str)))))))
(defun avy--overlay-post (path leaf)
"Create an overlay with PATH at LEAF.
str))
(avy--overlay
str
- (cond ((numberp leaf)
- leaf)
- ((consp (car leaf))
- (cdar leaf))
- (t
- (car leaf)))
- (if (consp leaf)
- (cdr leaf)
- (selected-window)))))
+ (avy-candidate-end leaf) nil
+ (avy-candidate-wnd leaf))))
+
+(defun avy--update-offset-and-str (offset str lep)
+ "Recalculate the length of the new overlay at point.
+
+OFFSET is the previous overlay length.
+STR is the overlay string that we wish to add.
+LEP is the line end position.
+
+We want to add an overlay between point and END=point+OFFSET.
+When other overlays already exist between point and END, set
+OFFSET to be the difference between the start of the first
+overlay and point. This is equivalent to truncating our new
+overlay, so that it doesn't intersect with overlays that already
+exist."
+ (let* ((wnd (selected-window))
+ (beg (point))
+ (oov (delq nil
+ (mapcar
+ (lambda (o)
+ (and (eq (overlay-get o 'category) 'avy)
+ (eq (overlay-get o 'window) wnd)
+ (overlay-start o)))
+ (overlays-in beg (min (+ beg offset) lep))))))
+ (when oov
+ (setq offset (- (apply #'min oov) beg))
+ (setq str (substring str 0 offset)))
+ (let ((other-ov (cl-find-if
+ (lambda (o)
+ (and (eq (overlay-get o 'category) 'avy)
+ (eq (overlay-start o) beg)
+ (not (eq (overlay-get o 'window) wnd))))
+ (overlays-in (point) (min (+ (point) offset) lep)))))
+ (when (and other-ov
+ (> (overlay-end other-ov)
+ (+ beg offset)))
+ (setq str (concat str (buffer-substring
+ (+ beg offset)
+ (overlay-end other-ov))))
+ (setq offset (- (overlay-end other-ov)
+ beg))))
+ (cons offset str)))
(defun avy--style-fn (style)
"Transform STYLE symbol to a style function."
(declare-function subword-backward "subword")
(defvar subword-backward-regexp)
+(defcustom avy-subword-extra-word-chars '(?{ ?= ?} ?* ?: ?> ?<)
+ "A list of characters that should temporarily match \"\\w\".
+This variable is used by `avy-goto-subword-0' and `avy-goto-subword-1'."
+ :type '(repeat character))
+
;;;###autoload
(defun avy-goto-subword-0 (&optional arg predicate)
"Jump to a word or subword start.
"\\(\\(\\W\\|[[:lower:][:digit:]]\\)\\([!-/:@`~[:upper:]]+\\W*\\)\\|\\W\\w+\\)")
candidates)
(avy-dowindows arg
- (let ((ws (window-start))
- window-cands)
- (save-excursion
- (goto-char (window-end (selected-window) t))
- (subword-backward)
- (while (> (point) ws)
- (when (or (null predicate)
- (and predicate (funcall predicate)))
- (unless (get-char-property (point) 'invisible)
- (push (cons (point) (selected-window)) window-cands)))
- (subword-backward)))
- (setq candidates (nconc candidates window-cands))))
+ (let ((syn-tbl (copy-syntax-table)))
+ (dolist (char avy-subword-extra-word-chars)
+ (modify-syntax-entry char "w" syn-tbl))
+ (with-syntax-table syn-tbl
+ (let ((ws (window-start))
+ window-cands)
+ (save-excursion
+ (goto-char (window-end (selected-window) t))
+ (subword-backward)
+ (while (> (point) ws)
+ (when (or (null predicate)
+ (and predicate (funcall predicate)))
+ (unless (get-char-property (point) 'invisible)
+ (push (cons (point) (selected-window)) window-cands)))
+ (subword-backward)))
+ (setq candidates (nconc candidates window-cands))))))
(avy--process candidates (avy--style-fn avy-style)))))
;;;###autoload
(point))
(selected-window)) candidates))
(if visual-line-mode
- (ignore-errors
- (line-move 1))
+ (progn
+ (setq temporary-goal-column 0)
+ (line-move-visual 1 t))
(forward-line 1)))))))
- (setq avy-action #'identity)
- (avy--process (nreverse candidates) (avy--style-fn avy-style))))
+ (let ((avy-action #'identity))
+ (avy--process (nreverse candidates) (avy--style-fn avy-style)))))
;;;###autoload
(defun avy-goto-line (&optional arg)
Otherwise, forward to `goto-line' with ARG."
(interactive "p")
+ (setq arg (or arg 1))
(if (not (memq arg '(1 4)))
(progn
(goto-char (point-min))
"Goto line: " (string char))))
(when line
(avy-push-mark)
- (goto-char (point-min))
- (forward-line (1- (string-to-number line)))
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (forward-line (1- (string-to-number line))))
(throw 'done 'exit))))))
(r (avy--line (eq arg 4))))
(unless (eq r t)
(defun avy-goto-line-above ()
"Goto visible line above the cursor."
(interactive)
- (let ((r (avy--line nil (window-start) (point))))
+ (let* ((avy-all-windows nil)
+ (r (avy--line nil (window-start)
+ (line-beginning-position))))
(unless (eq r t)
(avy-action-goto r))))
(defun avy-goto-line-below ()
"Goto visible line below the cursor."
(interactive)
- (let ((r (avy--line
- nil (point)
- (window-end (selected-window) t))))
+ (let* ((avy-all-windows nil)
+ (r (avy--line
+ nil (line-beginning-position 2)
+ (window-end (selected-window) t))))
(unless (eq r t)
(avy-action-goto r))))
+(defcustom avy-line-insert-style 'above
+ "How to insert the newly copied/cut line."
+ :type '(choice
+ (const :tag "Above" above)
+ (const :tag "Below" below)))
+
;;;###autoload
(defun avy-copy-line (arg)
"Copy a selected line above the current line.
ARG lines can be used."
(interactive "p")
- (avy-with avy-copy-line
- (let ((start (avy--line)))
- (move-beginning-of-line nil)
- (save-excursion
- (insert
- (buffer-substring-no-properties
- start
- (save-excursion
- (goto-char start)
- (move-end-of-line arg)
- (point)))
- "\n")))))
+ (let ((initial-window (selected-window)))
+ (avy-with avy-copy-line
+ (let* ((start (avy--line))
+ (str (buffer-substring-no-properties
+ start
+ (save-excursion
+ (goto-char start)
+ (move-end-of-line arg)
+ (point)))))
+ (select-window initial-window)
+ (cond ((eq avy-line-insert-style 'above)
+ (beginning-of-line)
+ (save-excursion
+ (insert str "\n")))
+ ((eq avy-line-insert-style 'below)
+ (end-of-line)
+ (insert "\n" str)
+ (beginning-of-line))
+ (t
+ (user-error "Unexpected `avy-line-insert-style'")))))))
;;;###autoload
(defun avy-move-line (arg)
"Move a selected line above the current line.
ARG lines can be used."
(interactive "p")
- (avy-with avy-move-line
- (let ((start (avy--line)))
- (move-beginning-of-line nil)
- (save-excursion
+ (let ((initial-window (selected-window)))
+ (avy-with avy-move-line
+ (let ((start (avy--line)))
(save-excursion
(goto-char start)
(kill-whole-line arg))
- (insert
- (current-kill 0))))))
+ (select-window initial-window)
+ (cond ((eq avy-line-insert-style 'above)
+ (beginning-of-line)
+ (save-excursion
+ (insert
+ (current-kill 0))))
+ ((eq avy-line-insert-style 'below)
+ (end-of-line)
+ (newline)
+ (save-excursion
+ (insert (substring (current-kill 0) 0 -1))))
+ (t
+ (user-error "Unexpected `avy-line-insert-style'")))))))
;;;###autoload
-(defun avy-copy-region ()
- "Select two lines and copy the text between them here."
- (interactive)
- (avy-with avy-copy-region
- (let ((beg (avy--line))
- (end (avy--line))
- (pad (if (bolp) "" "\n")))
- (move-beginning-of-line nil)
- (save-excursion
- (insert
- (buffer-substring-no-properties
- beg
- (save-excursion
- (goto-char end)
- (line-end-position)))
- pad)))))
+(defun avy-copy-region (arg)
+ "Select two lines and copy the text between them to point.
+
+The window scope is determined by `avy-all-windows' or
+`avy-all-windows-alt' when ARG is non-nil."
+ (interactive "P")
+ (let ((initial-window (selected-window)))
+ (avy-with avy-copy-region
+ (let* ((beg (save-selected-window
+ (avy--line arg)))
+ (end (avy--line arg))
+ (str (buffer-substring-no-properties
+ beg
+ (save-excursion
+ (goto-char end)
+ (line-end-position)))))
+ (select-window initial-window)
+ (cond ((eq avy-line-insert-style 'above)
+ (beginning-of-line)
+ (save-excursion
+ (insert str "\n")))
+ ((eq avy-line-insert-style 'below)
+ (end-of-line)
+ (newline)
+ (save-excursion
+ (insert str)))
+ (t
+ (user-error "Unexpected `avy-line-insert-style'")))))))
;;;###autoload
(defun avy-setup-default ()
(defcustom avy-timeout-seconds 0.5
"How many seconds to wait for the second char.")
-(defun avy--read-string-timer ()
- "Read as many chars as possible and return them as string.
+(defun avy--read-candidates ()
+ "Read as many chars as possible and return their occurences.
At least one char must be read, and then repeatedly one next char
may be read if it is entered before `avy-timeout-seconds'. `DEL'
deletes the last char entered, and `RET' exits with the currently
read string immediately instead of waiting for another char for
-`avy-timeout-seconds'."
+`avy-timeout-seconds'.
+The format of the result is the same as that of `avy--regex-candidates'.
+This function obeys `avy-all-windows' setting."
(let ((str "") char break overlays regex)
(unwind-protect
- (progn
- (while (and (not break)
- (setq char (read-char (format "char%s: "
- (if (string= str "")
- str
- (format " (%s)" str)))
- t
- (and (not (string= str ""))
- avy-timeout-seconds))))
- ;; Unhighlight
- (dolist (ov overlays)
- (delete-overlay ov))
- (setq overlays nil)
- (cond
- ;; Handle RET
- ((= char 13)
- (setq break t))
- ;; Handle DEL
- ((= char 127)
- (let ((l (length str)))
- (when (>= l 1)
- (setq str (substring str 0 (1- l))))))
- (t
- (setq str (concat str (list char)))))
- ;; Highlight
- (when (>= (length str) 1)
- (dolist (win (if avy-all-windows
- (window-list)
- (list (selected-window))))
- (with-selected-window win
- (save-excursion
- (goto-char (window-start))
- (setq regex (regexp-quote str))
- (while (re-search-forward regex (window-end) t)
- (unless (get-char-property (point) 'invisible)
- (let ((ov (make-overlay (match-beginning 0) (match-end 0))))
- (push ov overlays)
- (overlay-put ov 'window (selected-window))
- (overlay-put ov 'face 'avy-goto-char-timer-face)))))))))
- str)
+ (progn
+ (while (and (not break)
+ (setq char
+ (read-char (format "char%s: "
+ (if (string= str "")
+ str
+ (format " (%s)" str)))
+ t
+ (and (not (string= str ""))
+ avy-timeout-seconds))))
+ ;; Unhighlight
+ (dolist (ov overlays)
+ (delete-overlay ov))
+ (setq overlays nil)
+ (cond
+ ;; Handle RET
+ ((= char 13)
+ (setq break t))
+ ;; Handle DEL
+ ((= char 127)
+ (let ((l (length str)))
+ (when (>= l 1)
+ (setq str (substring str 0 (1- l))))))
+ (t
+ (setq str (concat str (list char)))))
+ ;; Highlight
+ (when (>= (length str) 1)
+ (let ((case-fold-search
+ (or avy-case-fold-search (string= str (downcase str))))
+ found)
+ (avy-dowindows current-prefix-arg
+ (dolist (pair (avy--find-visible-regions
+ (window-start)
+ (window-end (selected-window) t)))
+ (save-excursion
+ (goto-char (car pair))
+ (setq regex (regexp-quote str))
+ (while (re-search-forward regex (cdr pair) t)
+ (unless (get-char-property (1- (point)) 'invisible)
+ (let ((ov (make-overlay
+ (match-beginning 0)
+ (match-end 0))))
+ (setq found t)
+ (push ov overlays)
+ (overlay-put ov 'window (selected-window))
+ (overlay-put ov 'face 'avy-goto-char-timer-face)))))))
+ ;; No matches at all, so there's surely a typo in the input.
+ (unless found (beep)))))
+ (nreverse (mapcar (lambda (ov)
+ (cons (cons (overlay-start ov)
+ (overlay-end ov))
+ (overlay-get ov 'window)))
+ overlays)))
(dolist (ov overlays)
(delete-overlay ov)))))
"Read one or many consecutive chars and jump to the first one.
The window scope is determined by `avy-all-windows' (ARG negates it)."
(interactive "P")
- (let ((str (avy--read-string-timer)))
+ (let ((avy-all-windows (if arg
+ (not avy-all-windows)
+ avy-all-windows)))
(avy-with avy-goto-char-timer
- (avy--generic-jump
- (regexp-quote str)
- arg
- avy-style))))
+ (avy--process
+ (avy--read-candidates)
+ (avy--style-fn avy-style)))))
(defvar avy-ring (make-ring 20)
"Hold the window and point history.")