Update (<2018-12-16 Sun>): I don’t use ivy anymore (moved to helm), so I won’t maintain ivy-filthy-rich from now on.
ivy-rich pushed a new update that enables users to customize transformers, so there isn’t much difference in functionality between ivy-filthy-rich and ivy-rich, only minor variances. I’ll keep using and maintining ivy-filthy-rich. But It will **not** be in melpa since ivy-rich is already there.
This package adds more information on ivy candidates. It also allows you to customize what is the information and how are they displayed.
Inspired by ivy-rich.
Features
- add information to ivy buffer
- customizable position
- cuztomizable face
- more to come if I can think of any
The package is not in melpa, so you need to download and load it yourself.
(ivy-filthy-rich-mode)
(defcustom ivy-filthy-rich-padding ?\s
"The padding of `ivy-filthy-rich-delimiter'.
It is used when there are extra space.
The length of the pad has to be one.
If not, `ivy-filth-rich' will fallback to using space to pad.
Currently only support character, because `make-string' only accept that."
:type 'character
:group 'ivy-filthy-rich)
(defcustom ivy-filthy-rich-pad-side 'right
"The side which padding is pad to.
Either left or right.
Left means align right,
right means align left."
:type 'symbol
:group 'ivy-filthy-rich)
(defcustom ivy-filthy-rich-max-length 0
"The max length of one entry (one line on ivy buffer).
If it is zero, the max-length is (1- (frame-width))"
:type 'number
:group 'ivy-filthy-rich)
Basically, there are three steps in a full customization.
An info function is a function which you pass in a candidate and it returns some extra information about the candidate.
You can checkout default ones under
;;
;;; Info Function (Return info string list, used in format)
;;
For example:
(defun ivy-filthy-rich--get-major-mode (candidate)
"Return major mode of buffer (CANDIDATE)."
(let ((buffer (get-buffer candidate)))
(if buffer
(list (symbol-name (buffer-local-value 'major-mode buffer))))
'("")))
This function returns the major mode in which the candidate is. Actually, it returns a list, rather than a string. The reason is explained below.
Also, make sure your don’t return an empty list and handle errors properly in info function.
Now you need to declare a format for a particular ivy-function.
Default ones are under
;;
;;; Default formaat
;;
For example,
(defvar ivy-filthy-rich-default-switch-buffer-format
'(((value . (lambda (candidate)
(list (ivy-switch-buffer-transformer candidate)))) (prop . 0.2) (candidate . t))
((value . ivy-filthy-rich--get-major-mode) (prop . 0.2) (face . (:foreground "#61AFEF")))
((value . ivy-filthy-rich--get-dir) (prop . 0.6) (face . (:foreground "#98C379"))))
"The default format for `ivy-switch-buffer'.")
As you see, the format is a list of alists. Each alist is a piece of extra information (except candidate). And the list represents a line in ivy buffer.
The order of the infos is the order of them in ivy buffer, from left to right. Note that candidate doesn’t need to be the first one.
Avaliable keys for alists are:
- value
- the function that returns a list of possible information strings.
Those strings sorts from the longest to the shortest.
ivy-filth-rich
will try to use the longest string, if it doesn’t fit,ivy-filthy-rich
will try the next one, and so on. If the last on is still too long, it will be truncated. Original candidate is never truncated, actually, it will “eat” other parts’ space if there is not enough.Some ivy/counsel functions have default transformers, you might want to include them into your custom format. (like what I did in the example) A complete list can be found in source code under
;;;; Ivy default transformers
- prop
- the length that the info can occupy. It is a fraction against
ivy-filthy-rich-max-length
.0.3
means the piece of info will get 30% of the max length. All the props don’t have to add up to 1, though. For candidates, you can just assign a average number because they are never truncated. The extra space will be taken from other parts to ensure candidate will be displayed prpperly. - face
- The face you want the info be in.
- candidate
- A boolean that marks which info is original candidate. There can be only one candidate.
And there is no need to add
(candidate . nil)
to other infos.
Make your tranformer by lambda
and add it to ivy-filthy-rich-transformer-alist
.
Restart ivy-filthy-rich-mode
if its already on.
(add-to-list 'ivy-filthy-rich-transformer-alist (ivy-filthy-rich-make-transformer 'ivy-command-you-want-to-modify 'your-custom-format))
(add-to-list 'ivy-filthy-rich-transformer-alist '(ivy-function-you-want-to-modify . (lambda (candidate) (ivy-filthy-rich--format-candidate candidate your-customized-format))))
The two expressions are equivilant.
ivy-filthy-rich--format-candidate
takes a candidate string and a format, and returns the modified string.
- @Yevgnen for ivy-rich
- @seagle0128 for finding a bunch of bugs