From: Ken Manheimer Date: Sat, 23 Jan 2016 22:50:54 +0000 (-0500) Subject: Merge branch 'master' of git.sv.gnu.org:/srv/git/emacs/elpa X-Git-Url: https://code.delx.au/gnu-emacs-elpa/commitdiff_plain/360ed9017c595f9e1bef8b7b15feb3ca04d95ad2?hp=822d6284b0dc757a7537df2d1ed46e8a9187a9e2 Merge branch 'master' of git.sv.gnu.org:/srv/git/emacs/elpa --- diff --git a/.gitignore b/.gitignore index 72ebc0fe5..43c9d2b03 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,8 @@ packages/rudel packages/soap-client packages/w3 packages/xelb + +# Testing file +/archive +*.log +*.buildlog \ No newline at end of file diff --git a/GNUmakefile b/GNUmakefile index ad86a7f8d..d23d52316 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,4 +1,5 @@ # Makefile for GNU Emacs Lisp Package Archive. +# EMACS=emacs --batch @@ -190,3 +191,31 @@ all-in-place: $(extra_elcs) $(autoloads) $(pkg_descs) externals: $(EMACS) -l admin/archive-contents.el \ -f archive-add/remove/update-externals + + + + +################### Testing ############### + +PACKAGE_DIRS = $(shell find packages -maxdepth 1 -type d) +PACKAGES=$(subst /,,$(subst packages,,$(PACKAGE_DIRS))) + +TOP =$(shell pwd) + +define test_template +$(1)-test: + cd packages/$(1);\ + $(EMACS) -l $(TOP)/admin/ert-support.el \ + --eval "(ert-support-test-package \"$(TOP)\" '$(1))" \ + +$(1)-test-log: + $(MAKE) $(1)-test > packages/$(1)/$(1).log 2>&1 || { stat=ERROR; } +endef + +$(foreach package,$(PACKAGES),$(eval $(call test_template,$(package)))) + +PACKAGES_TESTS=$(addsuffix -test-log,$(PACKAGES)) +PACKAGES_LOG=$(foreach package,$(PACKAGES),packages/$(package)/$(package).log) + +check: $(PACKAGES_TESTS) + $(EMACS) -l ert -f ert-summarize-tests-batch-and-exit $(PACKAGES_LOG) diff --git a/admin/ert-support.el b/admin/ert-support.el new file mode 100644 index 000000000..93d1af8ff --- /dev/null +++ b/admin/ert-support.el @@ -0,0 +1,54 @@ +;; The contents of this file are subject to the GPL License, Version 3.0. + +;; Copyright (C) 2016, Free Software Foundation, Inc. + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +(defun ert-support-package-install (top-directory package) + ;; blitz default value and set up from elpa. + (setq package-archives + `(("local-elpa" . ,(concat top-directory "/archive/packages")))) + (setq package-user-dir + (make-temp-file "elpa-test" t)) + (package-initialize) + (package-refresh-contents) + (package-install package)) + +(defun ert-support-test-find-tests (package-directory package) + (or + (directory-files package-directory nil ".*-test.el$") + (directory-files package-directory nil ".*-tests.el$") + (let ((dir-test + (concat package-directory "/test"))) + (when (file-exists-p dir-test) + (directory-files dir-test))) + (let ((dir-tests + (concat package-directory "/tests"))) + (when (file-exists-p dir-tests) + (directory-files dir-tests))))) + +(defun ert-support-load-tests (package-directory package) + (mapc + (lambda(file) + (message "Loading test file... %s" (concat package-directory file)) + (load-file (concat package-directory file))) + (ert-support-test-find-tests package-directory package))) + +(defun ert-support-test-package (top-directory package) + (ert-support-package-install top-directory package) + (ert-support-load-tests + (concat top-directory "/packages/" (symbol-name package) "/") + package) + + (ert-run-tests-batch-and-exit t)) diff --git a/packages/avy/avy.el b/packages/avy/avy.el index a8a6a2524..45f212085 100644 --- a/packages/avy/avy.el +++ b/packages/avy/avy.el @@ -1,10 +1,10 @@ -;;; avy.el --- set-based completion -*- lexical-binding: t -*- +;;; avy.el --- tree-based completion -*- lexical-binding: t -*- ;; Copyright (C) 2015 Free Software Foundation, Inc. ;; Author: Oleh Krehel ;; URL: https://github.com/abo-abo/avy -;; Version: 0.3.0 +;; Version: 0.4.0 ;; Package-Requires: ((emacs "24.1") (cl-lib "0.5")) ;; Keywords: point, location @@ -28,9 +28,9 @@ ;; This package provides a generic completion method based on building ;; a balanced decision tree with each candidate being a leaf. To ;; traverse the tree from the root to a desired leaf, typically a -;; sequence of `read-char' can be used. +;; sequence of `read-key' can be used. ;; -;; In order for `read-char' to make sense, the tree needs to be +;; In order for `read-key' to make sense, the tree needs to be ;; visualized appropriately, with a character at each branch node. So ;; this completion method works only for things that you can see on ;; your screen, all at once: @@ -47,6 +47,7 @@ ;;; Code: (require 'cl-lib) +(require 'ring) ;;* Customization (defgroup avy nil @@ -55,8 +56,15 @@ :prefix "avy-") (defcustom avy-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l) - "Default keys for jumping." - :type '(repeat :tag "Keys" character)) + "Default keys for jumping. +Any key is either a character representing a self-inserting +key (letters, digits, punctuation, etc.) or a symbol denoting a +non-printing key like an arrow key (left, right, up, down). For +non-printing keys, a corresponding entry in +`avy-key-to-char-alist' must exist in order to visualize the key +in the avy overlays." + :type '(repeat :tag "Keys" (choice (character :tag "char") + (symbol :tag "non-printing key")))) (defcustom avy-keys-alist nil "Alist of avy-jump commands to `avy-keys' overriding the default `avy-keys'." @@ -105,7 +113,25 @@ If the commands isn't on the list, `avy-style' is used." (const :tag "Pre" pre) (const :tag "At" at) (const :tag "At Full" at-full) - (const :tag "Post" post)))) + (const :tag "Post" post) + (const :tag "De Bruijn" de-bruijn)))) + +(defcustom avy-dispatch-alist + '((?x . avy-action-kill) + (?m . avy-action-mark) + (?n . avy-action-copy)) + "List of actions for `avy-handler-default'. + +Each item is (KEY . ACTION). When KEY not on `avy-keys' is +pressed during the dispatch, ACTION is set to replace the default +`avy-action-goto' once a candidate is finally selected." + :type + '(alist + :key-type (choice (character :tag "Char")) + :value-type (choice + (const :tag "Mark" avy-action-mark) + (const :tag "Copy" avy-action-copy) + (const :tag "Kill" avy-action-kill)))) (defcustom avy-background nil "When non-nil, a gray background will be added during the selection." @@ -144,11 +170,11 @@ For example, to make SPC do the same as ?a, use "Face used for first non-terminating leading chars.") (defface avy-lead-face-1 - '((t (:foreground "white" :background "gray"))) + '((t (:foreground "white" :background "gray"))) "Face used for matched leading chars.") (defface avy-lead-face-2 - '((t (:foreground "white" :background "#f86bf3"))) + '((t (:foreground "white" :background "#f86bf3"))) "Face used for leading chars.") (defface avy-lead-face @@ -159,6 +185,10 @@ For example, to make SPC do the same as ?a, use '((t (:foreground "gray40"))) "Face for whole window background during selection.") +(defface avy-goto-char-timer-face + '((t (:inherit highlight))) + "Face for matches during reading chars using `avy-goto-char-timer'.") + (defconst avy-lead-faces '(avy-lead-face avy-lead-face-0 avy-lead-face-2 @@ -167,6 +197,16 @@ For example, to make SPC do the same as ?a, use avy-lead-face-2) "Face sequence for `avy--overlay-at-full'.") +(defvar avy-key-to-char-alist '((left . ?◀) + (right . ?▶) + (up . ?▲) + (down . ?▼) + (prior . ?△) + (next . ?▽)) + "An alist from non-character keys to printable chars used in avy overlays. +This alist must contain all keys used in `avy-keys' which are not +self-inserting keys and thus aren't read as characters.") + ;;* Internals ;;** Tree (defmacro avy-multipop (lst n) @@ -185,16 +225,16 @@ For example, to make SPC do the same as ?a, use (a (make-list (* n k) 0)) sequence) (cl-labels ((db (T p) - (if (> T n) - (if (eq (% n p) 0) - (setq sequence - (append sequence - (cl-subseq a 1 (1+ p))))) - (setf (nth T a) (nth (- T p) a)) - (db (1+ T) p) - (cl-loop for j from (1+ (nth (- T p) a)) to (1- k) do - (setf (nth T a) j) - (db (1+ T) T))))) + (if (> T n) + (if (eq (% n p) 0) + (setq sequence + (append sequence + (cl-subseq a 1 (1+ p))))) + (setf (nth T a) (nth (- T p) a)) + (db (1+ T) p) + (cl-loop for j from (1+ (nth (- T p) a)) to (1- k) do + (setf (nth T a) j) + (db (1+ T) T))))) (db 1 1) (mapcar (lambda (n) (nth n keys)) @@ -295,13 +335,21 @@ KEYS is the path from the root of `avy-tree' to LEAF." (funcall walker key (cddr br)) (avy-traverse (cdr br) walker key))))) +(defvar avy-action nil + "Function to call at the end of select.") + (defun avy-handler-default (char) - "The default hander for a bad CHAR." - (signal 'user-error (list "No such candidate" char)) - (throw 'done nil)) + "The default handler for a bad CHAR." + (let (dispatch) + (if (setq dispatch (assoc char avy-dispatch-alist)) + (progn + (setq avy-action (cdr dispatch)) + (throw 'done 'restart)) + (signal 'user-error (list "No such candidate" char)) + (throw 'done nil)))) (defvar avy-handler-function 'avy-handler-default - "A function to call for a bad `read-char' in `avy-read'.") + "A function to call for a bad `read-key' in `avy-read'.") (defvar avy-current-path "" "Store the current incomplete path during `avy-read'.") @@ -324,14 +372,14 @@ multiple DISPLAY-FN invokations." (push (cons path leaf) avy--leafs))) (dolist (x avy--leafs) (funcall display-fn (car x) (cdr x)))) - (let ((char (funcall avy-translate-char-function (read-char))) + (let ((char (funcall avy-translate-char-function (read-key))) branch) (funcall cleanup-fn) (if (setq branch (assoc char tree)) (if (eq (car (setq tree (cdr branch))) 'leaf) (throw 'done (cdr tree)) (setq avy-current-path - (concat avy-current-path (string char)))) + (concat avy-current-path (string (avy--key-to-char char))))) (funcall avy-handler-function char)))))) (defun avy-read-de-bruijn (lst keys) @@ -342,31 +390,32 @@ multiple DISPLAY-FN invokations." ;; 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-char)))) - (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 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 () @@ -383,69 +432,108 @@ multiple DISPLAY-FN invokations." (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 (unless (memq major-mode avy-ignored-modes) ,@body))))) -(defmacro avy--with-avy-keys (command &rest body) - "Set `avy-keys' according to COMMAND and execute BODY." +(defmacro avy-with (command &rest body) + "Set `avy-keys' according to COMMAND and execute BODY. +Set `avy-style' according to COMMMAND as well." (declare (indent 1) (debug (form body))) `(let ((avy-keys (or (cdr (assq ',command avy-keys-alist)) avy-keys)) (avy-style (or (cdr (assq ',command avy-styles-alist)) avy-style))) + (setq avy-action nil) ,@body)) -(defun avy--goto (x) - "Goto X. -X is (POS . WND) -POS is either a position or (BEG . END)." - (cond ((null x) - (message "zero candidates")) - - ;; ignore exit from `avy-handler-function' - ((eq x 'exit)) - - (t - (let* ((window (cdr x)) - (frame (window-frame window))) - (unless (equal frame (selected-frame)) - (select-frame-set-input-focus frame)) - (select-window window)) - (let ((pt (car x))) - (when (consp pt) - (setq pt (car pt))) - (unless (= pt (point)) (push-mark)) - (goto-char pt))))) +(defun avy-action-goto (pt) + "Goto PT." + (goto-char pt)) + +(defun avy-action-mark (pt) + "Mark sexp at PT." + (goto-char pt) + (set-mark (point)) + (forward-sexp)) + +(defun avy-action-copy (pt) + "Copy sexp starting on PT." + (save-excursion + (let (str) + (goto-char pt) + (forward-sexp) + (setq str (buffer-substring pt (point))) + (kill-new str) + (message "Copied: %s" str)))) + +(defun avy-action-kill (pt) + "Kill sexp at PT." + (goto-char pt) + (forward-sexp) + (kill-region pt (point)) + (message "Killed: %s" (current-kill 0))) (defun avy--process (candidates overlay-fn) "Select one of CANDIDATES using `avy-read'. Use OVERLAY-FN to visualize the decision overlay." - (unwind-protect - (cl-case (length candidates) - (0 - nil) - (1 - (car candidates)) - (t - (avy--make-backgrounds - (avy-window-list)) - (if (eq avy-style 'de-bruijn) - (avy-read-de-bruijn - candidates avy-keys) - (avy-read (avy-tree candidates avy-keys) - overlay-fn - #'avy--remove-leading-chars)))) - (avy--done))) + (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) + (if (= len 0) + (message "zero candidates") + (if (= len 1) + (setq res (car candidates)) + (unwind-protect + (progn + (avy--make-backgrounds + (avy-window-list)) + (setq res (if (eq avy-style 'de-bruijn) + (avy-read-de-bruijn + candidates avy-keys) + (avy-read (avy-tree candidates avy-keys) + overlay-fn + #'avy--remove-leading-chars)))) + (avy--done))) + (cond ((eq res 'restart) + (avy--process cands overlay-fn)) + ;; ignore exit from `avy-handler-function' + ((eq res 'exit)) + (t + (avy-push-mark) + (when (and (consp res) + (windowp (cdr res))) + (let* ((window (cdr res)) + (frame (window-frame window))) + (unless (equal frame (selected-frame)) + (select-frame-set-input-focus frame)) + (select-window window)) + (setq res (car res))) + + (funcall (or avy-action 'avy-action-goto) + (if (consp res) + (car res) + res))))))) (defvar avy--overlays-back nil "Hold overlays for when `avy-background' is t.") @@ -470,20 +558,53 @@ Use OVERLAY-FN to visualize the decision overlay." (setq avy--overlays-back nil) (avy--remove-leading-chars)) +(defun avy--next-visible-point () + "Return the next closest point without 'invisible property." + (let ((s (point))) + (while (and (not (= (point-max) (setq s (next-overlay-change s)))) + (get-char-property s 'invisible))) + s)) + +(defun avy--next-invisible-point () + "Return the next closest point with 'invisible property." + (let ((s (point))) + (while (and (not (= (point-max) (setq s (next-overlay-change s)))) + (not (get-char-property s 'invisible)))) + s)) + +(defun avy--find-visible-regions (rbeg rend) + "Return a list of all visible regions between RBEG and REND." + (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. Each element of the list is ((BEG . END) . WND) When PRED is non-nil, it's a filter for matching point positions. When GROUP is non-nil, (BEG . END) should delimit that regex group." (setq group (or group 0)) - (let ((case-fold-search avy-case-fold-search) + (let ((case-fold-search (or avy-case-fold-search + (string= regex (downcase regex)))) candidates) - (avy-dowindows nil - (let ((we (or end (window-end (selected-window) t)))) + (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 (or beg (window-start))) - (while (re-search-forward regex we t) - (unless (get-char-property (point) 'invisible) + (goto-char (car pair)) + (while (re-search-forward regex (cdr pair) t) + (unless (get-char-property (1- (point)) 'invisible) (when (or (null pred) (funcall pred)) (push (cons (cons (match-beginning group) @@ -502,31 +623,88 @@ When GROUP is non-nil, (BEG . END) should delimit that regex 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'. Do this even when the char is terminating." :type 'boolean) +(defun avy--key-to-char (c) + "If C is no character, translate it using `avy-key-to-char-alist'." + (if (characterp c) + c + (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. LEAF is normally ((BEG . END) . WND)." - (let ((str (propertize (apply #'string (reverse path)) - 'face 'avy-lead-face))) + (let* ((path (mapcar #'avy--key-to-char path)) + (str (propertize (apply #'string (reverse path)) + 'face 'avy-lead-face))) (when (or avy-highlight-first (> (length str) 1)) (set-text-properties 0 1 '(face avy-lead-face-0) str)) (setq str (concat @@ -535,54 +713,42 @@ LEAF is normally ((BEG . END) . WND)." 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. PATH is a list of keys from tree root to LEAF. LEAF is normally ((BEG . END) . WND)." - (let ((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))) - (let ((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") - str)) - (push ol avy--overlays-lead)))) + (let* ((path (mapcar #'avy--key-to-char path)) + (str (propertize + (string (car (last path))) + '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. PATH is a list of keys from tree root to LEAF. LEAF is normally ((BEG . END) . WND)." - (let* ((str (propertize + (let* ((path (mapcar #'avy--key-to-char path)) + (str (propertize (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)) @@ -596,63 +762,55 @@ LEAF is normally ((BEG . END) . WND)." (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 (- tab-width len) ?\ ))) - (t - 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. PATH is a list of keys from tree root to LEAF. LEAF is normally ((BEG . END) . WND)." - (let ((str (propertize (apply #'string (reverse path)) - 'face 'avy-lead-face))) + (let* ((path (mapcar #'avy--key-to-char path)) + (str (propertize (apply #'string (reverse path)) + 'face 'avy-lead-face))) (when (or avy-highlight-first (> (length str) 1)) (set-text-properties 0 1 '(face avy-lead-face-0) str)) (setq str (concat @@ -661,15 +819,49 @@ LEAF is normally ((BEG . END) . WND)." 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." @@ -681,27 +873,27 @@ LEAF is normally ((BEG . END) . WND)." (de-bruijn #'avy--overlay-at-full) (t (error "Unexpected style %S" style)))) -(defun avy--generic-jump (regex window-flip style) +(defun avy--generic-jump (regex window-flip style &optional beg end) "Jump to REGEX. When WINDOW-FLIP is non-nil, do the opposite of `avy-all-windows'. -STYLE determines the leading char overlay style." +STYLE determines the leading char overlay style. +BEG and END delimit the area where candidates are searched." (let ((avy-all-windows (if window-flip (not avy-all-windows) avy-all-windows))) - (avy--goto - (avy--process - (avy--regex-candidates regex) - (avy--style-fn style))))) + (avy--process + (avy--regex-candidates regex beg end) + (avy--style-fn style)))) ;;* Commands ;;;###autoload (defun avy-goto-char (char &optional arg) "Jump to the currently visible CHAR. The window scope is determined by `avy-all-windows' (ARG negates it)." - (interactive (list (read-char "char: ") + (interactive (list (read-char "char: " t) current-prefix-arg)) - (avy--with-avy-keys avy-goto-char + (avy-with avy-goto-char (avy--generic-jump (if (= 13 char) "\n" @@ -712,25 +904,23 @@ The window scope is determined by `avy-all-windows' (ARG negates it)." ;;;###autoload (defun avy-goto-char-in-line (char) "Jump to the currently visible CHAR in the current line." - (interactive (list (read-char "char: "))) - (let ((avy-all-windows nil)) - (avy--with-avy-keys avy-goto-char - (avy--goto - (avy--process - (save-restriction - (narrow-to-region (line-beginning-position) - (line-end-position)) - (avy--regex-candidates (regexp-quote (string char)))) - (avy--style-fn avy-style)))))) + (interactive (list (read-char "char: " t))) + (avy-with avy-goto-char + (avy--generic-jump + (regexp-quote (string char)) + avy-all-windows + avy-style + (line-beginning-position) + (line-end-position)))) ;;;###autoload (defun avy-goto-char-2 (char1 char2 &optional arg) "Jump to the currently visible CHAR1 followed by CHAR2. The window scope is determined by `avy-all-windows' (ARG negates it)." - (interactive (list (read-char "char 1: ") - (read-char "char 2: ") + (interactive (list (read-char "char 1: " t) + (read-char "char 2: " t) current-prefix-arg)) - (avy--with-avy-keys avy-goto-char-2 + (avy-with avy-goto-char-2 (avy--generic-jump (regexp-quote (string char1 char2)) arg @@ -740,30 +930,28 @@ The window scope is determined by `avy-all-windows' (ARG negates it)." (defun avy-isearch () "Jump to one of the current isearch candidates." (interactive) - (avy--with-avy-keys avy-isearch - (let* ((candidates - (avy--regex-candidates isearch-string)) - (avy-background nil) - (candidate - (avy--process candidates (avy--style-fn avy-style)))) - (isearch-done) - (avy--goto candidate)))) + (avy-with avy-isearch + (let ((avy-background nil)) + (avy--process + (avy--regex-candidates isearch-string) + (avy--style-fn avy-style)) + (isearch-done)))) ;;;###autoload (defun avy-goto-word-0 (arg) "Jump to a word start. The window scope is determined by `avy-all-windows' (ARG negates it)." (interactive "P") - (avy--with-avy-keys avy-goto-word-0 + (avy-with avy-goto-word-0 (avy--generic-jump "\\b\\sw" arg avy-style))) ;;;###autoload (defun avy-goto-word-1 (char &optional arg) "Jump to the currently visible CHAR at a word start. The window scope is determined by `avy-all-windows' (ARG negates it)." - (interactive (list (read-char "char: ") + (interactive (list (read-char "char: " t) current-prefix-arg)) - (avy--with-avy-keys avy-goto-word-1 + (avy-with avy-goto-word-1 (let* ((str (string char)) (regex (cond ((string= str ".") "\\.") @@ -777,6 +965,12 @@ The window scope is determined by `avy-all-windows' (ARG negates it)." (avy--generic-jump regex arg avy-style)))) (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) @@ -788,36 +982,43 @@ When PREDICATE is non-nil it's a function of zero parameters that should return true." (interactive "P") (require 'subword) - (avy--with-avy-keys avy-goto-subword-0 + (avy-with avy-goto-subword-0 (let ((case-fold-search nil) + (subword-backward-regexp + "\\(\\(\\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))) - (push (cons (point) (selected-window)) window-cands)) - (subword-backward))) - (setq candidates (nconc candidates window-cands)))) - (avy--goto - (avy--process candidates (avy--style-fn avy-style)))))) + (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 -(defun avy-goto-subword-1 (char arg) +(defun avy-goto-subword-1 (char &optional arg) "Jump to the currently visible CHAR at a subword start. The window scope is determined by `avy-all-windows' (ARG negates it). The case of CHAR is ignored." - (interactive (list (read-char "char: ") + (interactive (list (read-char "char: " t) current-prefix-arg)) - (avy--with-avy-keys avy-goto-subword-1 + (avy-with avy-goto-subword-1 (let ((char (downcase char))) (avy-goto-subword-0 arg (lambda () (eq (downcase (char-after)) char)))))) +;;;###autoload (defun avy-goto-word-or-subword-1 () "Forward to `avy-goto-subword-1' or `avy-goto-word-1'. Which one depends on variable `subword-mode'." @@ -826,16 +1027,18 @@ Which one depends on variable `subword-mode'." (call-interactively #'avy-goto-subword-1) (call-interactively #'avy-goto-word-1))) -(defun avy--line (&optional arg) +(defvar visual-line-mode) + +(defun avy--line (&optional arg beg end) "Select a line. -The window scope is determined by `avy-all-windows' (ARG negates it)." - (let ((avy-background nil) - candidates) +The window scope is determined by `avy-all-windows' (ARG negates it). +Narrow the scope to BEG END." + (let (candidates) (avy-dowindows arg - (let ((ws (window-start))) + (let ((ws (or beg (window-start)))) (save-excursion (save-restriction - (narrow-to-region ws (window-end (selected-window) t)) + (narrow-to-region ws (or end (window-end (selected-window) t))) (goto-char (point-min)) (while (< (point) (point-max)) (unless (get-char-property @@ -843,80 +1046,159 @@ The window scope is determined by `avy-all-windows' (ARG negates it)." (push (cons (if (eq avy-style 'post) (line-end-position) - (line-beginning-position)) + (point)) (selected-window)) candidates)) - (forward-line 1)))))) - (avy--process (nreverse candidates) (avy--style-fn avy-style)))) + (if visual-line-mode + (progn + (setq temporary-goal-column 0) + (line-move-visual 1 t)) + (forward-line 1))))))) + (let ((avy-action #'identity)) + (avy--process (nreverse candidates) (avy--style-fn avy-style))))) ;;;###autoload (defun avy-goto-line (&optional arg) "Jump to a line start in current buffer. -The window scope is determined by `avy-all-windows' (ARG negates it)." - (interactive "P") - (avy--with-avy-keys avy-goto-line - (let ((avy-handler-function - (lambda (char) - (if (or (< char ?0) - (> char ?9)) - (avy-handler-default char) - (let ((line (read-from-minibuffer - "Goto line: " (string char)))) - (when line - (goto-char (point-min)) - (forward-line (1- (string-to-number line))) - (throw 'done 'exit))))))) - (avy--goto (avy--line arg))))) + +When ARG is 1, jump to lines currently visible, with the option +to cancel to `goto-line' by entering a number. + +When ARG is 4, negate the window scope determined by +`avy-all-windows'. + +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)) + (forward-line (1- arg))) + (avy-with avy-goto-line + (let* ((avy-handler-function + (lambda (char) + (if (or (< char ?0) + (> char ?9)) + (avy-handler-default char) + (let ((line (read-from-minibuffer + "Goto line: " (string char)))) + (when line + (avy-push-mark) + (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) + (avy-action-goto r)))))) + +;;;###autoload +(defun avy-goto-line-above () + "Goto visible line above the cursor." + (interactive) + (let* ((avy-all-windows nil) + (r (avy--line nil (window-start) + (line-beginning-position)))) + (unless (eq r t) + (avy-action-goto r)))) + +;;;###autoload +(defun avy-goto-line-below () + "Goto visible line below the cursor." + (interactive) + (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-keys avy-copy-line - (let ((start (car (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-keys avy-move-line - (let ((start (car (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-keys avy-copy-region - (let ((beg (car (avy--line))) - (end (car (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 () @@ -927,49 +1209,120 @@ ARG lines can be used." (defcustom avy-timeout-seconds 0.5 "How many seconds to wait for the second char.") +(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'. +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) + (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))))) + ;;;###autoload (defun avy-goto-char-timer (&optional arg) - "Read one or two consecutive chars and jump to the first one. + "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 ((c1 (read-char "char 1: ")) - (c2 (read-char "char 2: " nil avy-timeout-seconds))) - (avy--with-avy-keys avy-goto-char-timer - (avy--generic-jump - (regexp-quote - (if c2 - (string c1 c2) - (string c1))) - arg - avy-style)))) - -(define-obsolete-variable-alias - 'avy-goto-char-style 'avy-style "0.1.0" - "Use `avy-style' and `avy-styles-alist' instead.") -(define-obsolete-variable-alias - 'avy-goto-word-style 'avy-style "0.1.0" - "Use `avy-style' and `avy-styles-alist' instead.") -(define-obsolete-variable-alias 'avi-keys 'avy-keys "0.1.0") -(define-obsolete-variable-alias 'avi-background 'avy-background "0.1.0") -(define-obsolete-variable-alias 'avi-word-punc-regexp 'avy-word-punc-regexp "0.1.0") -(define-obsolete-face-alias 'avi-lead-face 'avy-lead-face "0.1.0") -(define-obsolete-function-alias 'avi--goto 'avy--goto "0.1.0") -(define-obsolete-function-alias 'avi--process 'avy--process "0.1.0") -(define-obsolete-variable-alias 'avi-all-windows 'avy-all-windows "0.1.0") -(define-obsolete-function-alias 'avi--overlay-pre 'avy--overlay-pre "0.1.0") -(define-obsolete-function-alias 'avi--overlay-at 'avy--overlay-at "0.1.0") -(define-obsolete-function-alias 'avi--overlay-post 'avy--overlay-post "0.1.0") -(define-obsolete-function-alias 'avi-goto-char 'avy-goto-char "0.1.0") -(define-obsolete-function-alias 'avi-goto-char-2 'avy-goto-char-2 "0.1.0") -(define-obsolete-function-alias 'avi-isearch 'avy-isearch "0.1.0") -(define-obsolete-function-alias 'avi-goto-word-0 'avy-goto-word-0 "0.1.0") -(define-obsolete-function-alias 'avi-goto-subword-0 'avy-goto-subword-0 "0.1.0") -(define-obsolete-function-alias 'avi-goto-word-1 'avy-goto-word-1 "0.1.0") -(define-obsolete-function-alias 'avi-goto-line 'avy-goto-line "0.1.0") -(define-obsolete-function-alias 'avi-copy-line 'avy-copy-line "0.1.0") -(define-obsolete-function-alias 'avi-move-line 'avy-move-line "0.1.0") -(define-obsolete-function-alias 'avi-copy-region 'avy-copy-region "0.1.0") -(define-obsolete-function-alias 'avi--regex-candidates 'avy--regex-candidates "0.1.0") + (let ((avy-all-windows (if arg + (not avy-all-windows) + avy-all-windows))) + (avy-with avy-goto-char-timer + (avy--process + (avy--read-candidates) + (avy--style-fn avy-style))))) + +(defvar avy-ring (make-ring 20) + "Hold the window and point history.") + +(defun avy-push-mark () + "Store the current point and window." + (ring-insert avy-ring + (cons (point) (selected-window))) + (unless (region-active-p) + (push-mark))) + +(defun avy-pop-mark () + "Jump back to the last location of `avy-push-mark'." + (interactive) + (let (res) + (condition-case nil + (progn + (while (not (window-live-p + (cdr (setq res (ring-remove avy-ring 0)))))) + (let* ((window (cdr res)) + (frame (window-frame window))) + (when (and (frame-live-p frame) + (not (eq frame (selected-frame)))) + (select-frame-set-input-focus frame)) + (select-window window) + (goto-char (car res)))) + (error + (set-mark-command 4))))) + +(define-obsolete-function-alias + 'avy--goto 'identity "0.3.0" + "Don't use this function any more. +`avy--process' will do the jump all by itself.") + +(define-obsolete-function-alias 'avy--with-avy-keys 'avy-with "0.3.0") (provide 'avy) diff --git a/packages/avy/doc/Changelog.org b/packages/avy/doc/Changelog.org index 7dbcdf107..6d5b80c6b 100644 --- a/packages/avy/doc/Changelog.org +++ b/packages/avy/doc/Changelog.org @@ -205,7 +205,121 @@ Use this to restore the previous default behavior: #+begin_src elisp (setq avy-style 'pre) #+end_src - -* trunk +* 0.4.0 ** Fixes *** =avy-goto-char-timer= obeys =avy-styles-alist= +See [[https://github.com/abo-abo/avy/issues/67][#67]]. +*** Add =de-bruijn= to the defcustom of =avy-styles-alist= +See [[https://github.com/abo-abo/avy/issues/73][#73]]. +*** Respect the current input method for target chars +See [[https://github.com/abo-abo/avy/issues/76][#76]]. +*** =avy-goto-subword-0= shouldn't offer invisible chars +See [[https://github.com/abo-abo/avy/issues/90][#90]]. +*** Better =case-fold-search= handling +See [[https://github.com/abo-abo/avy/issues/87][#87]]. +*** Add misc punctuation to subword commands +See [[https://github.com/abo-abo/avy/issues/93][#93]]. +*** Add padding for wide-width chars (ex. Japanese and Chinese) +See [[https://github.com/abo-abo/avy/issues/96][#96]]. +*** =avy-goto-line= +**** Push mark for numeric line +See [[https://github.com/abo-abo/avy/issues/74][#74]]. +**** Allow numeric prefix arg +The old behavior remains for ARG 1 or 4. For all other ARG, simply go +to that line. +See [[https://github.com/abo-abo/avy/issues/86][#86]]. +**** Work for =visual-line-mode= +See [[https://github.com/abo-abo/avy/issues/91][#91]]. +**** Don't error on end of buffer +See [[https://github.com/abo-abo/avy/issues/91][#91]]. +**** Obey =avy-background= +See [[https://github.com/abo-abo/avy/issues/94][#94]]. +**** Fix for narrowed regions +See [[https://github.com/abo-abo/avy/issues/122][#122]], [[https://github.com/abo-abo/avy/issues/123][#123]]. +**** Don't modify =avy-action= +See [[https://github.com/abo-abo/avy/issues/124][#124]]. +*** =avy-goto-char-timer= +**** May read as many chars as you want +See [[https://github.com/abo-abo/avy/issues/97][#97]]. +**** Highlight matches while reading chars +See [[https://github.com/abo-abo/avy/issues/98][#98]]. +**** Highlight depending on =avy-all-windows= +See [[https://github.com/abo-abo/avy/issues/104][#104]]. +**** Make faster for =org-mode= +See [[https://github.com/abo-abo/avy/issues/100][#100]]. +**** Add case fold search +See [[https://github.com/abo-abo/avy/issues/128][#128]]. +*** =avy-copy-region= +**** Keep the same selectors for the second pass +See [[https://github.com/abo-abo/avy/issues/120][#120]], [[https://github.com/abo-abo/avy/issues/121][#121]]. +**** Copy/move to initial window +See [[https://github.com/abo-abo/avy/issues/131][#131]]. +*** Search only in the visible region +See [[https://github.com/abo-abo/avy/issues/108][#108]], [[https://github.com/abo-abo/avy/issues/109][#109]]. +*** Fix jumping to the last char of a folded Org outline +See [[https://github.com/abo-abo/avy/issues/108][#108]]. +*** Fix for both =org-indent-mode= and =visual-line-mode= +See [[https://github.com/abo-abo/avy/issues/110][#110]]. +*** Beep when there are no matches +See [[https://github.com/abo-abo/avy/issues/111][#111]]. +*** Simplify overlay code +Most functions reuse =avy--overlay= now. +*** Fix de-bruijn "no catch for tag" +See [[https://github.com/abo-abo/avy/issues/116][#116]]. +*** Fix overlays at =point-max= +See [[https://github.com/abo-abo/avy/issues/125][#125]]. +*** Improve =case-fold-search= condition +See [[https://github.com/abo-abo/avy/issues/126][#126]]. +*** Don't shorten selector string for =visual-line-mode= and =bolp= +See [[https://github.com/abo-abo/avy/issues/129][#129]]. +*** Fix interaction with =goto-address-mode= +** New Features +*** Allow non-printing keys in =avy-keys= +Now you can set avy-keys also to the arrow keys and page up/down, e.g. + +#+begin_src elisp +(setq avy-keys '(left right up down prior next)) +#+end_src + +and those will be displayed as ▲, ▼, ◀, ▶, △, ▽ in the overlays. The +display is controlled by the variable =avy-key-to-char-alist=. + +See [[https://github.com/abo-abo/avy/issues/77][#77]]. +*** Allow to switch action midway from goto to kill/mark/copy +For example, suppose you have: + +#+begin_src elisp +(global-set-key (kbd "M-t") 'avy-goto-word-1) +#+end_src + +- To jump to a certain word starting with "w" (e.g. first one on + screen): ~M-t w a~ +- To copy the word instead of jumping to it: ~M-t w na~. +- To mark the word after jumping to it: ~M-t w ma~. +- To kill the word after jumping to it: ~M-t w xa~. + +You can customize =avy-dispatch-alist= to modify these actions. + +See [[https://github.com/abo-abo/avy/issues/78][#78]]. + +*** New command =avy-pop-mark= +Goes back to the last location of =push-mark=: + +- has its own history, +- handles multiple frames. + +See [[https://github.com/abo-abo/avy/issues/81][#81]] [[https://github.com/abo-abo/avy/issues/88][#88]] [[https://github.com/abo-abo/avy/issues/69][#69]]. +*** New commands =avy-goto-line-above= and =avy-goto-line-below= +See [[https://github.com/abo-abo/avy/issues/106][#106]]. +*** New defcustom =avy-line-insert-style= +Allows to modify the behavior of =avy-copy-line=, =avy-move-line=, and =avy-copy-region=. +See [[https://github.com/abo-abo/avy/issues/117][#117]]. +*** New defcustom =avy-all-windows-alt= +Allows to customize the behavior of =universal-argument= modifying +=avy-all-windows=. +See [[https://github.com/abo-abo/avy/issues/118][#118]]. +*** New defcustom =avy-subword-extra-word-chars= +Allows to customize the behavior of =avy-goto-subword-0= and +=avy-goto-subword-1= by adding extra chars that should match as word +constituents. +See [[https://github.com/abo-abo/avy/issues/116][#116]]. diff --git a/packages/yasnippet/doc/doc/.nosearch b/packages/yasnippet/doc/.nosearch similarity index 100% rename from packages/yasnippet/doc/doc/.nosearch rename to packages/yasnippet/doc/.nosearch diff --git a/packages/yasnippet/doc/doc/faq.org b/packages/yasnippet/doc/faq.org similarity index 100% rename from packages/yasnippet/doc/doc/faq.org rename to packages/yasnippet/doc/faq.org diff --git a/packages/yasnippet/doc/doc/index.org b/packages/yasnippet/doc/index.org similarity index 100% rename from packages/yasnippet/doc/doc/index.org rename to packages/yasnippet/doc/index.org diff --git a/packages/yasnippet/doc/doc/nav-menu.html.inc b/packages/yasnippet/doc/nav-menu.html.inc similarity index 100% rename from packages/yasnippet/doc/doc/nav-menu.html.inc rename to packages/yasnippet/doc/nav-menu.html.inc diff --git a/packages/yasnippet/doc/doc/org-setup.inc b/packages/yasnippet/doc/org-setup.inc similarity index 100% rename from packages/yasnippet/doc/doc/org-setup.inc rename to packages/yasnippet/doc/org-setup.inc diff --git a/packages/yasnippet/doc/doc/snippet-development.org b/packages/yasnippet/doc/snippet-development.org similarity index 100% rename from packages/yasnippet/doc/doc/snippet-development.org rename to packages/yasnippet/doc/snippet-development.org diff --git a/packages/yasnippet/doc/doc/snippet-expansion.org b/packages/yasnippet/doc/snippet-expansion.org similarity index 100% rename from packages/yasnippet/doc/doc/snippet-expansion.org rename to packages/yasnippet/doc/snippet-expansion.org diff --git a/packages/yasnippet/doc/doc/snippet-menu.org b/packages/yasnippet/doc/snippet-menu.org similarity index 100% rename from packages/yasnippet/doc/doc/snippet-menu.org rename to packages/yasnippet/doc/snippet-menu.org diff --git a/packages/yasnippet/doc/doc/snippet-organization.org b/packages/yasnippet/doc/snippet-organization.org similarity index 100% rename from packages/yasnippet/doc/doc/snippet-organization.org rename to packages/yasnippet/doc/snippet-organization.org diff --git a/packages/yasnippet/doc/doc/snippet-reference.org b/packages/yasnippet/doc/snippet-reference.org similarity index 100% rename from packages/yasnippet/doc/doc/snippet-reference.org rename to packages/yasnippet/doc/snippet-reference.org diff --git a/packages/yasnippet/doc/doc/stylesheets/manual.css b/packages/yasnippet/doc/stylesheets/manual.css similarity index 100% rename from packages/yasnippet/doc/doc/stylesheets/manual.css rename to packages/yasnippet/doc/stylesheets/manual.css