abo-abo / swiper

Ivy - a generic completion frontend for Emacs, Swiper - isearch with an overview, and more. Oh, man!
https://oremacs.com/swiper/
2.3k stars 338 forks source link

ivy: long prompts truncated, completions not shown #974

Open eigengrau opened 7 years ago

eigengrau commented 7 years ago

Currently, when ivy inserts a prompt wider than the Emacs frame, the minibuffer window will be scrolled to the right, hiding the beginning of the prompt and potentially all completions (in case they are shorter than the hidden part of the prompt). It would be convenient if the line would wrap visually like completing-read-default or ido do.

abo-abo commented 7 years ago

Can't reproduce with:

(ivy-read "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttest: " '("one" "two"))
eigengrau commented 7 years ago

Okay, playing around with emacs -Q a bit, this seems to crop up in certain contexts when the minibuffer face has a height or font different from the default face.

(set-face-attribute 'default nil :family "Inconsolata" :height 130)
(defun my-minibuffer-setup ()
  (set (make-local-variable 'face-remapping-alist)
       '((default :family "Inconsolata" :height 200))))
(add-hook 'minibuffer-setup-hook #'my-minibuffer-setup)
(set-frame-size (window-frame) 50 50)
(read-file-name "123 123 123 123 123 123 123")

This yields me this:

screenshot

I see ivy does some width/height calculations. Could the face-remapping from my custom hook mess this up somehow?

abo-abo commented 7 years ago

You can turn off line truncation in your hook:

(defun my-minibuffer-setup ()
  (set (make-local-variable 'face-remapping-alist)
       '((default :family "Inconsolata" :height 200)))
  (setq truncate-lines nil))

I think the truncation was turned on (a long time ago) to prevent candidates from occupying more than one line. The truncation rule for the prompt and the candidates is the same, since they are in the same buffer.

eigengrau commented 7 years ago

Ah, I should have been able to tell from the fringe indicators that truncate-lines must have been set. Seeing that this looked like a visual quirk, I suspected something much less straightforward. Thank you kindly for the pointer and thanks for making swiper/ivy!

abo-abo commented 7 years ago

You're welcome.

eigengrau commented 7 years ago

I realize now that disabling truncate-lines wholesale might not be entirely desirable. E.g., with swiper it’s not uncommon that search hits are wider than the minibuffer, and wrapping them will clutter the interface quite a bit.

I wonder whether it’s possible to only wrap the prompt line, but truncate the rest? In a way this is what ivy seems to already do, is it? Am I correct that it’s the font-remapping that breaks this? Is it possible for ivy to take the effects of this into account?

eigengrau commented 7 years ago

I’m not sure the code I’m looking at is relevant to this issue, but in places where width calculations are being done, ivy seems to be using frame-char-width to get the width of a character. The width returned by this seems to only return the width of the globally set default face. I wonder whether using window-font-width resp. default-font-width would help us here; this appears to have been added in Emacs 25.

Edit: Nevermind, I only found frame-char-height in the code, not width.

abo-abo commented 7 years ago

I don't have a quick fix, but I'm open to suggestions.