- ;;; consel.el --- Elisp completion at point -*- lexical-binding: t -*-
+ ;;; counsel.el --- Various completion functions using Ivy -*- lexical-binding: t -*-
;; Copyright (C) 2015 Free Software Foundation, Inc.
;; Author: Oleh Krehel <ohwoeowho@gmail.com>
+ ;; URL: https://github.com/abo-abo/swiper
+ ;; Version: 0.1.0
+ ;; Package-Requires: ((emacs "24.1") (ivy "0.2.1"))
+ ;; Keywords: completion, matching
;; This file is part of GNU Emacs.
;;; Commentary:
;;
- ;; Just call `counsel' to start completing the `obarray'.
- ;; The initial (optional) input is thing-at-point.
+ ;; Just call one of the interactive functions in this file to complete
+ ;; the corresponding thing using `ivy'.
+ ;;
+ ;; Currently available: Elisp symbols, Clojure symbols, Git files.
;;; Code:
(require 'ivy)
- (defun counsel ()
+ (defun counsel-el ()
"Elisp completion at point."
(interactive)
(counsel--generic
(lambda (str) (all-completions str obarray))))
- (defun couns-clj ()
+ (defun counsel-describe-variable (variable &optional buffer frame)
+ "Forward to (`describe-variable' VARIABLE BUFFER FRAME)."
+ (interactive
+ (let ((v (variable-at-point))
+ (enable-recursive-minibuffers t)
+ (preselect (thing-at-point 'symbol))
+ val)
+ (setq val (ivy-read
+ (if (symbolp v)
+ (format
+ "Describe variable (default %s): " v)
+ "Describe variable: ")
+ (let (cands)
+ (mapatoms
+ (lambda (vv)
+ (when (or (get vv 'variable-documentation)
+ (and (boundp vv) (not (keywordp vv))))
+ (push (symbol-name vv) cands))))
+ cands)
+ nil nil preselect))
+ (list (if (equal val "")
+ v
+ (intern val)))))
+ (describe-variable variable buffer frame))
+
+ (defun counsel-describe-function (function)
+ "Forward to (`describe-function' FUNCTION) with ivy completion."
+ (interactive
+ (let ((fn (function-called-at-point))
+ (enable-recursive-minibuffers t)
+ (preselect (thing-at-point 'symbol))
+ val)
+ (setq val (ivy-read (if fn
+ (format "Describe function (default %s): " fn)
+ "Describe function: ")
+ (let (cands)
+ (mapatoms
+ (lambda (x)
+ (when (fboundp x)
+ (push (symbol-name x) cands))))
+ cands)
+ nil nil preselect))
+ (list (if (equal val "")
+ fn (intern val)))))
+ (describe-function function))
+
+ (defvar info-lookup-mode)
+ (declare-function info-lookup->completions "info-look")
+ (declare-function info-lookup->mode-value "info-look")
+ (declare-function info-lookup-select-mode "info-look")
+ (declare-function info-lookup-change-mode "info-look")
+ (declare-function info-lookup "info-look")
+
+ (defun counsel-info-lookup-symbol (symbol &optional mode)
+ "Forward to (`info-describe-symbol' SYMBOL MODE) with ivy completion."
+ (interactive
+ (progn
+ (require 'info-look)
+ (let* ((topic 'symbol)
+ (mode (cond (current-prefix-arg
+ (info-lookup-change-mode topic))
+ ((info-lookup->mode-value
+ topic (info-lookup-select-mode))
+ info-lookup-mode)
+ ((info-lookup-change-mode topic))))
+ (completions (info-lookup->completions topic mode))
+ (enable-recursive-minibuffers t)
+ (value (ivy-read
+ "Describe symbol: "
+ (mapcar #'car completions))))
+ (list value info-lookup-mode))))
+ (info-lookup 'symbol symbol mode))
+
+ (defun counsel-unicode-char ()
+ "Insert a Unicode character at point."
+ (interactive)
+ (let* ((minibuffer-allow-text-properties t)
+ (char (ivy-read "Unicode name: "
+ (mapcar (lambda (x)
+ (propertize
+ (format "% -60s%c" (car x) (cdr x))
+ 'result (cdr x)))
+ (ucs-names)))))
+ (insert-char (get-text-property 0 'result char))))
+
+ (defun counsel-clj ()
"Clojure completion at point."
(interactive)
(counsel--generic
(lambda (str)
(mapcar
#'cl-caddr
- (cider-sync-request:complete str ":same")))))
+ (with-no-warnings
+ (cider-sync-request:complete str ":same"))))))
- (defun couns-git ()
+ (defun counsel-git ()
"Find file in the current Git repository."
(interactive)
(let* ((default-directory (locate-dominating-file
;; Author: Oleh Krehel <ohwoeowho@gmail.com>
;; URL: https://github.com/abo-abo/swiper
- ;; Version: 0.2.0
+ ;; Version: 0.2.1
;; Package-Requires: ((emacs "24.1"))
;; Keywords: matching
"Whether to wrap around after the first and last candidate."
:type 'boolean)
+ (defcustom ivy-on-del-error-function 'minibuffer-keyboard-quit
+ "The handler for when `ivy-backward-delete-char' throws.
+ This is usually meant as a quick exit out of the minibuffer."
+ :type 'function)
+
;;* User Visible
;;** Keymap
(require 'delsel)
(interactive)
(setq ivy--index (1- ivy--length)))
- (defun ivy-next-line ()
- "Select the next completion candidate."
- (interactive)
- (if (>= ivy--index (1- ivy--length))
- (when ivy-wrap
- (ivy-beginning-of-buffer))
- (cl-incf ivy--index)))
-
- (defun ivy-next-line-or-history ()
- "Select the next completion candidate.
+ (defun ivy-next-line (&optional arg)
+ "Move cursor vertically down ARG candidates."
+ (interactive "p")
+ (setq arg (or arg 1))
+ (cl-incf ivy--index arg)
+ (when (>= ivy--index (1- ivy--length))
+ (if ivy-wrap
+ (ivy-beginning-of-buffer)
+ (setq ivy--index (1- ivy--length)))))
+
+ (defun ivy-next-line-or-history (&optional arg)
+ "Move cursor vertically down ARG candidates.
If the input is empty, select the previous history element instead."
- (interactive)
+ (interactive "p")
(when (string= ivy-text "")
(ivy-previous-history-element 1))
- (if (>= ivy--index (1- ivy--length))
- (when ivy-wrap
- (ivy-beginning-of-buffer))
- (cl-incf ivy--index)))
-
- (defun ivy-previous-line ()
- "Select the previous completion candidate."
- (interactive)
- (if (zerop ivy--index)
- (when ivy-wrap
- (ivy-end-of-buffer))
- (cl-decf ivy--index)))
+ (ivy-next-line arg))
- (defun ivy-previous-line-or-history ()
- "Select the previous completion candidate.
+ (defun ivy-previous-line (&optional arg)
+ "Move cursor vertically up ARG candidates."
+ (interactive "p")
+ (setq arg (or arg 1))
+ (cl-decf ivy--index arg)
+ (when (< ivy--index 0)
+ (if ivy-wrap
+ (ivy-end-of-buffer)
+ (setq ivy--index 0))))
+
+ (defun ivy-previous-line-or-history (arg)
+ "Move cursor vertically up ARG candidates.
If the input is empty, select the previous history element instead."
- (interactive)
+ (interactive "p")
(when (string= ivy-text "")
(ivy-previous-history-element 1))
- (if (zerop ivy--index)
- (when ivy-wrap
- (ivy-end-of-buffer))
- (cl-decf ivy--index)))
+ (ivy-previous-line arg))
(defun ivy-previous-history-element (arg)
"Forward to `previous-history-element' with ARG."
(defun ivy-backward-delete-char ()
"Forward to `backward-delete-char'.
- On error (read-only), quit without selecting."
+ On error (read-only), call `ivy-on-del-error-function'."
(interactive)
(condition-case nil
(backward-delete-char 1)
(error
- (minibuffer-keyboard-quit))))
+ (when ivy-on-del-error-function
+ (funcall ivy-on-del-error-function)))))
;;** Entry Point
(defun ivy-read (prompt collection
PROMPT is a string to prompt with; normally it ends in a colon
and a space. When PROMPT contains %d, it will be updated with
the current number of matching candidates.
+ See also `ivy-count-format'.
COLLECTION is a list of strings.
If INITIAL-INPUT is non-nil, insert it in the minibuffer initially.
- UPDATE-FN is called each time the current candidate(s) is changed.
+ KEYMAP is composed together with `ivy-minibuffer-map'.
If PRESELECT is non-nil select the corresponding candidate out of
the ones that match INITIAL-INPUT.
- KEYMAP is composed together with `ivy-minibuffer-map'."
+ UPDATE-FN is called each time the current candidate(s) is changed."
(cl-case (length collection)
(0 nil)
(1 (car collection))
(when ivy--action
(funcall ivy--action))))))
+ (defun ivy-completing-read (prompt collection
+ &optional predicate _require-match initial-input
+ &rest _ignore)
+ "Read a string in the minibuffer, with completion.
+
+ This is an interface that conforms to `completing-read', so that
+ it can be used for `completing-read-function'.
+
+ PROMPT is a string to prompt with; normally it ends in a colon and a space.
+ COLLECTION can be a list of strings, an alist, an obarray or a hash table.
+ PREDICATE limits completion to a subset of COLLECTION.
+
+ _REQUIRE-MATCH is ignored for now.
+ INITIAL-INPUT is a string that can be inserted into the minibuffer initially.
+
+ The history, defaults and input-method arguments are ignored for now."
+ (cond ((functionp collection)
+ (error "Function as a collection unsupported"))
+ ((hash-table-p collection)
+ (error "Hash table as a collection unsupported"))
+ ((listp (car collection))
+ (setq collection (mapcar #'car collection))))
+ (when predicate
+ (setq collection (cl-remove-if-not predicate collection)))
+ (ivy-read prompt collection initial-input))
+
+ ;;;###autoload
+ (define-minor-mode ivy-mode
+ "Toggle Ivy mode on or off.
+ With ARG, turn Ivy mode on if arg is positive, off otherwise.
+ Turning on Ivy mode will set `completing-read-function' to
+ `ivy-completing-read'."
+ :group 'ivy
+ :global t
+ :lighter " ivy"
+ (if ivy-mode
+ (setq completing-read-function 'ivy-completing-read)
+ (setq completing-read-function 'completing-read-default)))
+
(defvar ivy--action nil
"Store a function to call at the end of `ivy--read'.")
(cands (if (and (equal re ivy--old-re)
ivy--old-cands)
ivy--old-cands
- (setq ivy--old-re re)
(ignore-errors
(cl-remove-if-not
(lambda (x) (string-match re x))
(tail (nthcdr ivy--index ivy--old-cands))
(ww (window-width))
idx)
- (setq ivy--length (length cands))
(when (and tail ivy--old-cands)
- (while (and tail
- (null (setq idx (cl-position (pop tail) cands
- :test #'equal)))))
- (setq ivy--index (or idx 0)))
+ (unless (and (not (equal re ivy--old-re))
+ (setq ivy--index (cl-position re cands :test 'equal)))
+ (while (and tail (null idx))
+ ;; Compare with eq to handle equal duplicates in cands
+ (setq idx (cl-position (pop tail) cands)))
+ (setq ivy--index (or idx 0))))
+ (setq ivy--old-re re)
+ (setq ivy--length (length cands))
(setq ivy--old-cands cands)
(when (>= ivy--index ivy--length)
(setq ivy--index (max (1- ivy--length) 0)))
;; Author: Oleh Krehel <ohwoeowho@gmail.com>
;; URL: https://github.com/abo-abo/swiper
- ;; Version: 0.2.0
- ;; Package-Requires: ((emacs "24.1"))
+ ;; Version: 0.2.1
+ ;; Package-Requires: ((emacs "24.1") (ivy "0.2.1"))
;; Keywords: matching
;; This file is part of GNU Emacs.
(defvar swiper-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "M-q") 'swiper-query-replace)
+ (define-key map (kbd "C-l") 'swiper-recenter-top-bottom)
map)
"Keymap for swiper.")
(interactive)
(if (null (window-minibuffer-p))
(user-error "Should only be called in the minibuffer through `swiper-map'")
- (let* ((from (ivy--regex ivy-text))
+ (let* ((enable-recursive-minibuffers t)
+ (from (ivy--regex ivy-text))
(to (query-replace-read-to from "Query replace" t)))
(delete-minibuffer-contents)
(setq ivy--action
(swiper--cleanup)
(exit-minibuffer))))
+ (defun swiper-recenter-top-bottom (&optional arg)
+ "Call (`recenter-top-bottom' ARG) in `swiper--window'."
+ (interactive "P")
+ (with-selected-window swiper--window
+ (recenter-top-bottom arg)))
+
(defvar swiper--window nil
"Store the current window.")
gnus-summary-mode
gnus-article-mode
gnus-group-mode
- emms-playlist-mode erc-mode)))
+ emms-playlist-mode erc-mode
+ org-agenda-mode)))
(if (fboundp 'font-lock-ensure)
(font-lock-ensure)
(font-lock-fontify-buffer))))
(line-beginning-position)
(line-end-position)))
candidates)
- (zerop (forward-line 1)))
+ (forward-line 1))
(nreverse candidates))))))
(defvar swiper--opoint 1
(forward-line (1- num))
(isearch-range-invisible (line-beginning-position)
(line-end-position))
- (unless (and (> (point) (window-start))
- (< (point) (window-end swiper--window t)))
+ (unless (and (>= (point) (window-start))
+ (<= (point) (window-end swiper--window t)))
(recenter)))
(let ((ov (make-overlay
(line-beginning-position)