changeset 633: |
88a3f078c185 |
parent 632: |
bbd9024f2fe2 |
child 634: |
8eef7df3242d |
author: |
Richard Westhaver <ellis@rwest.io> |
date: |
Sun, 01 Sep 2024 21:00:12 -0400 |
files: |
emacs/lib/corfu-terminal.el |
description: |
add corfu-terminal |
1.1--- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2+++ b/emacs/lib/corfu-terminal.el Sun Sep 01 21:00:12 2024 -0400
1.3@@ -0,0 +1,225 @@
1.4+;;; corfu-terminal.el --- Corfu popup on terminal -*- lexical-binding: t; -*-
1.5+
1.6+;; Copyright (C) 2022 Akib Azmain Turja.
1.7+
1.8+;; Author: Akib Azmain Turja <akib@disroot.org>
1.9+;; Created: 2022-04-11
1.10+;; Version: 0.7
1.11+;; Package-Requires: ((emacs "26.1") (corfu "0.36") (popon "0.13"))
1.12+;; Keywords: convenience
1.13+;; Homepage: https://codeberg.org/akib/emacs-corfu-terminal
1.14+
1.15+;; This file is not part of GNU Emacs.
1.16+
1.17+;; This file is free software; you can redistribute it and/or modify
1.18+;; it under the terms of the GNU General Public License as published by
1.19+;; the Free Software Foundation; either version 3, or (at your option)
1.20+;; any later version.
1.21+
1.22+;; This program is distributed in the hope that it will be useful,
1.23+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
1.24+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.25+;; GNU General Public License for more details.
1.26+
1.27+;; For a full copy of the GNU General Public License
1.28+;; see <https://www.gnu.org/licenses/>.
1.29+
1.30+;;; Commentary:
1.31+
1.32+;; Corfu uses child frames to display candidates. This makes Corfu
1.33+;; unusable on terminal. This package replaces that with popup/popon,
1.34+;; which works everywhere. Use M-x corfu-terminal-mode to enable.
1.35+;; You'll probably want to enable it only on terminal. In that case,
1.36+;; put the following in your init file:
1.37+
1.38+;; (unless (display-graphic-p)
1.39+;; (corfu-terminal-mode +1))
1.40+
1.41+;;; Code:
1.42+
1.43+(require 'subr-x)
1.44+(require 'corfu)
1.45+(require 'popon)
1.46+(require 'cl-lib)
1.47+
1.48+(defgroup corfu-terminal nil
1.49+ "Corfu popup on terminal."
1.50+ :group 'convenience
1.51+ :link '(url-link "https://codeberg.org/akib/emacs-corfu-terminal")
1.52+ :prefix "corfu-terminal-")
1.53+
1.54+(defcustom corfu-terminal-enable-on-minibuffer t
1.55+ "Non-nil means enable corfu-terminal on minibuffer."
1.56+ :type 'boolean)
1.57+
1.58+(defcustom corfu-terminal-resize-minibuffer t
1.59+ "Non-nil means resize minibuffer to show popup."
1.60+ :type 'boolean)
1.61+
1.62+(defcustom corfu-terminal-position-right-margin 0
1.63+ "Number of columns of margin at the right of window.
1.64+
1.65+Always keep the popup this many columns away from the right edge of
1.66+the window.
1.67+
1.68+Note: If the popup breaks or crosses the right edge of window, you may
1.69+set this variable to warkaround it. But remember, that's a *bug*, so
1.70+if that ever happens to you please report the issue at
1.71+https://codeberg.org/akib/emacs-corfu-terminal/issues."
1.72+ :type 'integer)
1.73+
1.74+(defcustom corfu-terminal-disable-on-gui t
1.75+ "Don't use popon UI on GUI."
1.76+ :type '(choice (const :tag "Yes" t)
1.77+ (const :tag "No" nil)))
1.78+
1.79+(defvar corfu-terminal--popon nil
1.80+ "Popon object.")
1.81+
1.82+(defvar corfu-terminal--last-position nil
1.83+ "Position of last popon, and some data to make sure that's valid.")
1.84+
1.85+(cl-defmethod corfu--popup-support-p (&context (corfu-terminal-mode
1.86+ (eql t)))
1.87+ "Return whether corfu-terminal supports showing popon now."
1.88+ (or (not (minibufferp))
1.89+ corfu-terminal-enable-on-minibuffer
1.90+ (and corfu-terminal-disable-on-gui
1.91+ (display-graphic-p))))
1.92+
1.93+(cl-defmethod corfu--popup-hide (&context (corfu-terminal-mode
1.94+ (eql t)))
1.95+ "Hide popup.
1.96+
1.97+If `corfu-terminal-disable-on-gui' is non-nil and `display-graphic-p'
1.98+returns non-nil then call FN instead, where FN should be the original
1.99+definition in Corfu."
1.100+ (if (and corfu-terminal-disable-on-gui
1.101+ (display-graphic-p))
1.102+ (cl-call-next-method)
1.103+ (when corfu-terminal--popon
1.104+ (setq corfu-terminal--popon
1.105+ (popon-kill corfu-terminal--popon)))))
1.106+
1.107+(cl-defmethod corfu--popup-show ( pos off width lines
1.108+ &context (corfu-terminal-mode
1.109+ (eql t))
1.110+ &optional curr lo bar)
1.111+ "Show popup at OFF columns before POS.
1.112+
1.113+Show LINES, a list of lines. Highlight CURRth line as current
1.114+selection. Show a vertical scroll bar of size BAR + 1 from LOth line.
1.115+
1.116+If `corfu-terminal-disable-on-gui' is non-nil and `display-graphic-p'
1.117+returns non-nil then call FN instead, where FN should be the original
1.118+definition in Corfu."
1.119+ (if (and corfu-terminal-disable-on-gui
1.120+ (display-graphic-p))
1.121+ (cl-call-next-method)
1.122+ (corfu--popup-hide) ; Hide the popup first.
1.123+ (when (and (window-minibuffer-p)
1.124+ (< (/ (window-body-height nil 'pixelwise)
1.125+ (default-font-height))
1.126+ (1+ (length lines)))
1.127+ corfu-terminal-resize-minibuffer
1.128+ (not (frame-root-window-p (selected-window))))
1.129+ (window-resize nil (- (1+ (length lines))
1.130+ (/ (window-body-height nil 'pixelwise)
1.131+ (default-font-height)))))
1.132+ (let* ((bar-width (ceiling (* (default-font-width)
1.133+ corfu-bar-width)))
1.134+ (margin-left-width (ceiling (* (default-font-width)
1.135+ corfu-left-margin-width)))
1.136+ (margin-right-width (max (ceiling
1.137+ (* (default-font-width)
1.138+ corfu-right-margin-width))
1.139+ bar-width))
1.140+ (scroll-bar
1.141+ (when (< 0 bar-width)
1.142+ (if (display-graphic-p)
1.143+ (concat
1.144+ (propertize
1.145+ " " 'display
1.146+ `(space
1.147+ :width (,(- margin-right-width bar-width))))
1.148+ (propertize " " 'display
1.149+ `(space :width (,bar-width))
1.150+ 'face 'corfu-bar))
1.151+ (concat
1.152+ (make-string (- margin-right-width bar-width) ?\ )
1.153+ (propertize (make-string bar-width ?\ ) 'face
1.154+ 'corfu-bar)))))
1.155+ (margin-left
1.156+ (when (> margin-left-width 0)
1.157+ (if (display-graphic-p)
1.158+ (propertize
1.159+ " " 'display `(space :width (,margin-left-width)))
1.160+ (make-string margin-left-width ?\ ))))
1.161+ (margin-right
1.162+ (when (> margin-right-width 0)
1.163+ (if (display-graphic-p)
1.164+ (propertize
1.165+ " " 'display `(space :width (,margin-right-width)))
1.166+ (make-string margin-right-width ?\ ))))
1.167+ (popon-width
1.168+ (if (display-graphic-p)
1.169+ (+ width (round (/ (+ margin-left-width
1.170+ margin-right-width)
1.171+ (default-font-width))))
1.172+ (+ width margin-left-width margin-right-width)))
1.173+ (popon-pos
1.174+ (if (equal (cdr corfu-terminal--last-position)
1.175+ (list (posn-point pos) popon-width
1.176+ (window-start) (buffer-modified-tick)))
1.177+ (car corfu-terminal--last-position)
1.178+ (let ((x-y (popon-x-y-at-posn pos)))
1.179+ (cons
1.180+ (max
1.181+ (min (- (car x-y) (+ off margin-left-width))
1.182+ (- (window-max-chars-per-line)
1.183+ corfu-terminal-position-right-margin
1.184+ popon-width))
1.185+ 0)
1.186+ (if (and (< (/ (window-body-height nil 'pixelwise)
1.187+ (default-font-height))
1.188+ (+ (1+ (cdr x-y)) (length lines)))
1.189+ (>= (cdr x-y) (length lines)))
1.190+ (- (cdr x-y) (length lines))
1.191+ (1+ (cdr x-y))))))))
1.192+ (setq corfu-terminal--last-position
1.193+ (list popon-pos (posn-point pos) popon-width
1.194+ (window-start) (buffer-modified-tick)))
1.195+ (setq corfu-terminal--popon
1.196+ (popon-create
1.197+ (cons
1.198+ (string-join
1.199+ (seq-map-indexed
1.200+ (lambda (line line-number)
1.201+ (let ((str
1.202+ (concat
1.203+ margin-left line
1.204+ (make-string (- width (string-width line))
1.205+ ?\ )
1.206+ (if (and lo (<= lo line-number (+ lo bar)))
1.207+ scroll-bar
1.208+ margin-right))))
1.209+ (add-face-text-property 0 (length str)
1.210+ (if (eq line-number curr)
1.211+ 'corfu-current
1.212+ 'corfu-default)
1.213+ t str)
1.214+ str))
1.215+ lines)
1.216+ "\n")
1.217+ popon-width)
1.218+ popon-pos))
1.219+ nil)))
1.220+
1.221+;;;###autoload
1.222+(define-minor-mode corfu-terminal-mode
1.223+ "Corfu popup on terminal."
1.224+ :global t
1.225+ :group 'corfu-terminal)
1.226+
1.227+(provide 'corfu-terminal)
1.228+;;; corfu-terminal.el ends here