;;; ivy-overlay.el --- Overlay display functions for Ivy -*- lexical-binding: t -*-
|
|
|
|
;; Copyright (C) 2016-2019 Free Software Foundation, Inc.
|
|
|
|
;; Author: Oleh Krehel <ohwoeowho@gmail.com>
|
|
;; Keywords: convenience
|
|
|
|
;; 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 <https://www.gnu.org/licenses/>.
|
|
|
|
;;; Commentary:
|
|
|
|
;; This package allows to setup Ivy's completion at point to actually
|
|
;; show the candidates and the input at point, instead of in the
|
|
;; minibuffer.
|
|
|
|
;;; Code:
|
|
|
|
(defface ivy-cursor
|
|
'((((class color) (background light))
|
|
:background "black" :foreground "white")
|
|
(((class color) (background dark))
|
|
:background "white" :foreground "black"))
|
|
"Cursor face for inline completion."
|
|
:group 'ivy-faces)
|
|
|
|
(defvar ivy--old-cursor-type t)
|
|
|
|
(defvar ivy-overlay-at nil
|
|
"Overlay variable for `ivy-display-function-overlay'.")
|
|
|
|
(declare-function ivy--truncate-string "ivy")
|
|
|
|
(defun ivy-left-pad (str width)
|
|
"Return STR, but with each line indented by WIDTH spaces.
|
|
Lines are truncated to the window width."
|
|
(let ((padding (make-string width ?\s)))
|
|
(mapconcat (lambda (x)
|
|
(ivy--truncate-string (concat padding x)
|
|
(1- (+ (window-width)
|
|
(window-hscroll)))))
|
|
(split-string str "\n")
|
|
"\n")))
|
|
|
|
(defun ivy-overlay-cleanup ()
|
|
"Clean up after `ivy-display-function-overlay'."
|
|
(when (overlayp ivy-overlay-at)
|
|
(delete-overlay ivy-overlay-at)
|
|
(setq ivy-overlay-at nil))
|
|
(unless cursor-type
|
|
(setq cursor-type ivy--old-cursor-type))
|
|
(when (fboundp 'company-abort)
|
|
(company-abort)))
|
|
|
|
(defvar ivy-height)
|
|
|
|
(defun ivy-overlay-show-after (str)
|
|
"Display STR in an overlay at point.
|
|
|
|
First, fill each line of STR with spaces to the current column.
|
|
Then attach the overlay to the character before point."
|
|
(if ivy-overlay-at
|
|
(progn
|
|
(move-overlay ivy-overlay-at (1- (point)) (line-end-position))
|
|
(overlay-put ivy-overlay-at 'invisible nil))
|
|
(let ((available-height (count-lines (point) (window-end nil t))))
|
|
(unless (>= available-height ivy-height)
|
|
(recenter (- (window-height) ivy-height 2))))
|
|
(setq ivy-overlay-at (make-overlay (1- (point)) (line-end-position)))
|
|
;; Specify face to avoid clashing with other overlays.
|
|
(overlay-put ivy-overlay-at 'face 'default)
|
|
(overlay-put ivy-overlay-at 'priority 9999))
|
|
(overlay-put ivy-overlay-at 'display str)
|
|
(overlay-put ivy-overlay-at 'after-string ""))
|
|
|
|
(declare-function org-current-level "org")
|
|
(declare-function org-at-heading-p "org")
|
|
(defvar org-indent-indentation-per-level)
|
|
(defvar ivy-height)
|
|
(defvar ivy-last)
|
|
(defvar ivy-text)
|
|
(defvar ivy-completion-beg)
|
|
(declare-function ivy-add-face-text-property "ivy")
|
|
(declare-function ivy--get-window "ivy")
|
|
(declare-function ivy-state-current "ivy")
|
|
(declare-function ivy-state-window "ivy")
|
|
(declare-function ivy--remove-prefix "ivy")
|
|
|
|
(defun ivy-overlay-impossible-p (_str)
|
|
(or
|
|
(and (eq major-mode 'org-mode)
|
|
(plist-get (text-properties-at (point)) 'src-block))
|
|
(<= (window-height) (+ ivy-height 2))
|
|
(= (point) (point-min))
|
|
(< (- (+ (window-width) (window-hscroll)) (current-column))
|
|
30)))
|
|
|
|
(defun ivy-display-function-overlay (str)
|
|
"Called from the minibuffer, display STR in an overlay in Ivy window.
|
|
Hide the minibuffer contents and cursor."
|
|
(if (save-selected-window
|
|
(select-window (ivy-state-window ivy-last))
|
|
(ivy-overlay-impossible-p str))
|
|
(let ((buffer-undo-list t))
|
|
(save-excursion
|
|
(forward-line 1)
|
|
(insert str)))
|
|
(ivy-add-face-text-property (minibuffer-prompt-end) (point-max)
|
|
'(:foreground "white"))
|
|
(setq cursor-type nil)
|
|
(with-selected-window (ivy--get-window ivy-last)
|
|
(when cursor-type
|
|
(setq ivy--old-cursor-type cursor-type))
|
|
(setq cursor-type nil)
|
|
(let ((overlay-str
|
|
(apply
|
|
#'concat
|
|
(buffer-substring (max (point-min) (1- (point))) (point))
|
|
ivy-text
|
|
(and (eolp) " ")
|
|
(buffer-substring (point) (line-end-position))
|
|
(and (> (length str) 0)
|
|
(list "\n"
|
|
(ivy-left-pad
|
|
(ivy--remove-prefix "\n" str)
|
|
(+
|
|
(if (and (eq major-mode 'org-mode)
|
|
(bound-and-true-p org-indent-mode))
|
|
(if (org-at-heading-p)
|
|
(1- (org-current-level))
|
|
(* org-indent-indentation-per-level (org-current-level)))
|
|
0)
|
|
(save-excursion
|
|
(when ivy-completion-beg
|
|
(goto-char ivy-completion-beg))
|
|
(current-column)))))))))
|
|
(let ((cursor-offset (1+ (length ivy-text))))
|
|
(ivy-add-face-text-property cursor-offset (1+ cursor-offset)
|
|
'ivy-cursor overlay-str t))
|
|
(ivy-overlay-show-after overlay-str)))))
|
|
|
|
(provide 'ivy-overlay)
|
|
|
|
;;; ivy-overlay.el ends here
|