:group 'convenience)
(defface ivy-current-match
- '((t (:inherit highlight)))
+ '((((class color) (background light))
+ :background "#1a4b77" :foreground "white")
+ (((class color) (background dark))
+ :background "#65a7e2" :foreground "black"))
"Face used by Ivy for highlighting first match.")
(defface ivy-confirm-face
"Whether to wrap around after the first and last candidate."
:type 'boolean)
+(defcustom ivy-display-style nil
+ "The style for formatting the minibuffer.
+
+By default, the matched strings will be copied as they are.
+
+With the fancy method, the matching parts of the regexp will be
+additionally highlighted, just like `swiper' does it."
+ :type '(choice
+ (const :tag "Plain" nil)
+ (const :tag "Fancy" fancy)))
+
(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."
(set (make-local-variable 'minibuffer-default-add-function)
(lambda ()
(list ivy--default)))
- (setq line-spacing 0)
+ (when (and (display-graphic-p) (= (length (frame-list)) 1))
+ (setq truncate-lines t))
(setq-local max-mini-window-height ivy-height)
(add-hook 'post-command-hook #'ivy--exhibit nil t)
;; show completions with empty input
(let ((buffer-undo-list t))
(save-excursion
(forward-line 1)
- (insert text))))))
+ (insert text))))
+ (when (display-graphic-p)
+ (ivy--resize-minibuffer-to-fit))))
+
+(defun ivy--resize-minibuffer-to-fit ()
+ "Resize the minibuffer window so it has enough space to display
+all of the text contained in the minibuffer."
+ (with-selected-window (minibuffer-window)
+ (if (fboundp 'window-text-pixel-size)
+ (let ((text-height (cdr (window-text-pixel-size)))
+ (body-height (window-body-height nil t)))
+ (when (> text-height body-height)
+ (window-resize nil (- text-height body-height) nil t t)))
+ (fit-window-to-buffer))))
(declare-function colir-blend-face-background "ext:colir")
`propertize' or `add-face-text-property' in this case."
(require 'colir)
(condition-case nil
- (colir-blend-face-background 0 (length str) face str)
+ (progn
+ (colir-blend-face-background 0 (length str) face str)
+ (let ((foreground (face-foreground face)))
+ (when foreground
+ (add-face-text-property
+ 0 (length str)
+ `(:foreground ,foreground)
+ nil
+ str))))
(error
(ignore-errors
(font-lock-append-text-property 0 (length str) 'face face str))))
"Return all items that match NAME in CANDIDATES.
CANDIDATES are assumed to be static."
(let* ((re (funcall ivy--regex-function name))
+ (re-str (if (listp re) (caar re) re))
(matcher (ivy-state-matcher ivy-last))
(case-fold-search (string= name (downcase name)))
(cands (cond
(tail (nthcdr ivy--index ivy--old-cands))
idx)
(when (and tail ivy--old-cands (not (equal "^" ivy--old-re)))
- (unless (and (not (equal re ivy--old-re))
+ (unless (and (not (equal re-str ivy--old-re))
(or (setq ivy--index
(or
- (cl-position (if (and (> (length re) 0)
- (eq ?^ (aref re 0)))
- (substring re 1)
- re) cands
+ (cl-position (if (and (> (length re-str) 0)
+ (eq ?^ (aref re-str 0)))
+ (substring re-str 1)
+ re-str) cands
:test #'equal)
(and ivy--directory
(cl-position
- (concat re "/") cands
+ (concat re-str "/") cands
:test #'equal))))))
(while (and tail (null idx))
;; Compare with eq to handle equal duplicates in cands
(or (cl-position (ivy-state-preselect ivy-last)
cands :test #'equal)
ivy--index)))
- (setq ivy--old-re (if cands re ""))
+ (setq ivy--old-re (if cands re-str ""))
(setq ivy--old-cands cands)))
(defvar ivy-format-function 'ivy-format-function-default
(defun ivy-format-function-default (cands)
"Transform CANDS into a string for minibuffer."
- (let ((ww (window-width)))
- (mapconcat
- (lambda (s)
- (if (> (length s) ww)
- (concat (substring s 0 (- ww 3)) "...")
- s))
- cands "\n")))
+ (if (bound-and-true-p truncate-lines)
+ (mapconcat #'identity cands "\n")
+ (let ((ww (- (window-width)
+ (if (and (boundp 'fringe-mode) (eq fringe-mode 0)) 1 0))))
+ (mapconcat
+ (lambda (s)
+ (if (> (length s) ww)
+ (concat (substring s 0 (- ww 3)) "...")
+ s))
+ cands "\n"))))
(defun ivy-format-function-arrow (cands)
"Transform CANDS into a string for minibuffer."
s))
cands "\n")))
+(defcustom swiper-minibuffer-faces
+ '(swiper-minibuffer-match-face-1
+ swiper-minibuffer-match-face-2
+ swiper-minibuffer-match-face-3
+ swiper-minibuffer-match-face-4)
+ "List of `swiper' faces for minibuffer group matches.")
+
+(defun ivy--format-minibuffer-line (str)
+ (let ((start 0)
+ (str (copy-sequence str)))
+ (when (eq ivy-display-style 'fancy)
+ (unless ivy--old-re
+ (setq ivy--old-re (funcall ivy--regex-function ivy-text)))
+ (while (and (string-match ivy--old-re str start)
+ (> (- (match-end 0) (match-beginning 0)) 0))
+ (setq start (match-end 0))
+ (let ((i 0))
+ (while (<= i ivy--subexps)
+ (let ((face
+ (cond ((zerop ivy--subexps)
+ (cadr swiper-minibuffer-faces))
+ ((zerop i)
+ (car swiper-minibuffer-faces))
+ (t
+ (nth (1+ (mod (+ i 2) (1- (length swiper-minibuffer-faces))))
+ swiper-minibuffer-faces)))))
+ (add-face-text-property
+ (match-beginning i)
+ (match-end i)
+ face
+ nil
+ str))
+ (cl-incf i)))))
+ str))
+
(defun ivy--format (cands)
"Return a string for CANDS suitable for display in the minibuffer.
CANDS is a list of strings."
x))
cands)))
(setq ivy--current (copy-sequence (nth index cands)))
- (setf (nth index cands)
- (ivy--add-face ivy--current 'ivy-current-match))
(setq cands (mapcar
- (lambda (s)
- (let ((s (copy-sequence s)))
- (when (fboundp 'add-face-text-property)
- (add-face-text-property
- 0 (length s)
- `(:height ,(face-attribute 'default :height)
- :overline nil) nil s))
- s))
+ #'ivy--format-minibuffer-line
cands))
+ (setf (nth index cands)
+ (ivy--add-face (nth index cands) 'ivy-current-match))
(let* ((ivy--index index)
(res (concat "\n" (funcall ivy-format-function cands))))
(put-text-property 0 (length res) 'read-only nil res)