branch: externals/kind-icon commit fcfe9ead6b332e88a6bf7f4e55a9c47d65b619ab Author: JD Smith <93749+jdtsm...@users.noreply.github.com> Commit: JD Smith <93749+jdtsm...@users.noreply.github.com>
kind-icon-formatted: 3 char-width icon/centered 1 or 2 char text --- kind-icon.el | 165 ++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 107 insertions(+), 58 deletions(-) diff --git a/kind-icon.el b/kind-icon.el index 36484a6..b24782e 100644 --- a/kind-icon.el +++ b/kind-icon.el @@ -5,28 +5,47 @@ ;; Author: J.D. Smith ;; Homepage: https://github.com/jdtsmith/kind-icon ;; Package-Requires: ((emacs "27.1")) -;; Package-Version: 0.0.1 +;; Package-Version: 0.1.0 ;; Keywords: completion ;;; Commentary: -;; kind-icon-mode adds an icon or text prefix based on :company-kind -;; for compatible completion UI's utilizing completion-in-region. The -;; "kind" prefix is typically used for differentiating variables, -;; functions, etc. among completion results. It works by creating and -;; setting into `completion-extra-properties' a custom -;; affixation-function. This function creates, styles, and caches a +;; kind-icon-mode adds an colorful icon or text prefix based on +;; :company-kind for compatible completion UI's. The "kind" prefix is +;; typically used for differentiating completion candidates such as +;; variables, functions, etc. It works in one of 2 ways: +;; +;; 1. For UI's with a "kind-formatter" option, simply set that +;; function to `kind-icon-formatted'. +;; +;; 2. For UI's without a kind-formatter but which support "affixation +;; functions" (an Emacs 28 and later completion property), use +;; `kind-icon-enhance-completion' to wrap the normal +;; completion-in-region-function. E.g. (in the completion mode's +;; hook): +;; +;; (setq completion-in-region-function +;; (kind-icon-enhance-completion completion-in-region-function) +;; +;; 3. If your UI supports neither a kind-formatter nor affixation +;; functions, ask them to do so! +;; +;; Note that icon support requires svg-lib to be installed. +;; +;; The `kind-icon-formatted' function creates, styles, and caches a ;; short-text or icon-based "badge" representing the kind of the -;; candidate. Icons are by default loaded from the "material" library -;; provided by svg-lib, which is required (unless only short-text -;; badges are desired, see `kind-icon-use-icons'). +;; candidate. Icons are by default loaded remotely from the +;; "material" library provided by svg-lib, which is required (unless +;; only short-text badges are desired, see `kind-icon-use-icons'). +;; Customize `kind-icon-mapping' to configure mapping between kind and +;; both short-text and icons. ;; kind-icon 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. -;; Python-MLS is distributed in the hope that it will be useful, +;; kind-icon 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. @@ -79,16 +98,23 @@ "Mapping of kinds. The format should be an alist of type: - (KIND SHORT-TEXT LIBRARY ICON FACE-OR-COLOR) + (KIND SHORT-TEXT PLIST) This information is used to build a prefix for kind KIND. A -prefix is a propertized string of either the-short TEXT or -ICON (from LIBRARY; see `svg-icon'), depending on the value of -variable `kind-icon-use-icons' . FACE-OR-COLOR can either be a -color string or a face from which we the :foreground -face-property is taken. The background is automatically computed -to lie between the background color and foreground (see -`kind-icon-blend-frac')." +prefix is a propertized string of either an icon or the +SHORT-TEXT (two characters max), depending on the value of +variable `kind-icon-use-icons' and presence of :icon in the +PLIST. The PLIST is optional and includes keywords :icon and +:face. :icon is a name of an icon from the material +collection (see `svg-lib'). :face is a face from which the +:foreground face-property is used for the foreground. If +`kind-icon-blend-background' is non-nil, the icon's background +color is automatically computed to lie between the default-face +or frame background color and the foreground color (see +`kind-icon-blend-frac'). If `kind-icon-blend-background' is nil, +the background color is taken from the :face's background in this +map, or, if that is missing or unspecified, from the frame's +background color." :link '(url-link "https://materialdesignicons.com") :type '(repeat (list :tag "Mapping" @@ -102,10 +128,14 @@ to lie between the background color and foreground (see :action kind-icon--preview)) (:face (face :tag "Face"))))))) +(defcustom kind-icon-blend-background t + "Whether to set a custom background blended from foreground." + :type 'boolean) + (defcustom kind-icon-blend-frac 0.12 "Fractional blend between foreground and background colors. -This is used for the background for the short-text kind -prefixes." +This is used for the prefix background, if +kind-icon-blend-background is non-nil." :type 'float) (defcustom kind-icon-default-face nil @@ -113,10 +143,9 @@ prefixes." Normally foreground colors are supplied by the face matching in `kind-icon-mapping', but if no face is supplied in the mapping, the foreground color is taken from the foreground of this face, -or (if nil) to the default frame foreground color. The background -color for blending the foreground into the background is also -taken from this face, if provided, defaulting to the frame -background color." +or (if nil) to the default frame foreground color. The +background color is also taken from this face, if provided, +otherwise defaulting to the frame background color." :type 'face) (defcustom kind-icon-default-style @@ -125,7 +154,7 @@ background color." See `svg-lib-style-compute-default'." :type 'plist) -(defun kind-icon--preview (widget event) +(defun kind-icon--preview (_w _e) (goto-char (field-end)) (let ((icon (buffer-substring (point) (field-end)))) (message "%S looks like: %s" icon @@ -142,50 +171,68 @@ float FRAC." (+ (* a frac) (* b (- 1.0 frac)))) rgb1 rgb2))) -(defconst kind-icon--unknown - (propertize "??" 'face '(:weight bold :foreground "Red"))) - (defsubst kind-icon--metdata-get (metadata type-name) (or (cdr (assq (intern type-name) metadata)) (plist-get completion-extra-properties (intern (format ":%s" type-name))))) -(defun kind-icon-badge (kind) - "Return a kind badge, either an SVG icon or short-text abbreviation. -Caches as :display-icon in `kind-icon-mapping', and returns the -cached value, if set. For the background color, computes a blend -between a nominal background color (from either the frame -background color, or the :background property -`kind-icon-default-face', if set). See -`kind-icon-blend-frac'. For the foreground color, uses the -:face mapping's :foreground color, the `kind-icon-default-face' +(defun kind-icon-formatted (kind) + "Return a formatted kind badge, either icon or text abbreviation. +Caches this badge as :display-icon in `kind-icon-mapping', and +returns the cached value, if set. If +`kind-icon-blend-background' is non-nil, computes a blend between +a nominal background color (from either the background property +of `kind-icon-default-face', if set, or frame background color) +and foreground. For the foreground color, uses the :face +mapping's :foreground color, the `kind-icon-default-face' foreground, or the default frame foreground, in that order of -priority." +priority. If `kind-icon-blend-background' is nil, the background +is taken from the :face background, `kind-icon-default-face`, or +frame background-color." (when-let ((map (assq kind kind-icon-mapping)) (plist (cddr map))) (or (plist-get plist :display-icon) - (let* ((bg-rgb (color-name-to-rgb - (if kind-icon-default-face - (face-attribute kind-icon-default-face :background nil t) - (frame-parameter nil 'background-color)))) - (col-face (plist-get plist :face)) - (col (if col-face - (face-attribute col-face :foreground) + (let* ((kind-face (plist-get plist :face)) + (col (if kind-face + (face-attribute kind-face :foreground nil t) (if kind-icon-default-face (face-attribute kind-icon-default-face :foreground nil t) (frame-parameter nil 'foreground-color)))) - (bg-col (kind-icon--rgb-blend - (color-name-to-rgb col) bg-rgb - kind-icon-blend-frac)) + (kind-face-bg (and kind-face (face-attribute kind-face :background nil t))) + (default-bg (if kind-icon-default-face + (face-attribute kind-icon-default-face :background nil t) + (frame-parameter nil 'background-color))) + (bg-col (if kind-icon-blend-background + (kind-icon--rgb-blend + (color-name-to-rgb col) + (color-name-to-rgb default-bg) + kind-icon-blend-frac) + (if (and kind-face-bg (not (eq kind-face-bg 'unspecified))) + kind-face-bg + default-bg))) + (dfw (default-font-width)) + (half (/ dfw 2)) + (pad-right (propertize " " 'display `(space :width (,half)))) + (pad-left (propertize " " 'display `(space :width (,(- dfw half))))) (disp (if-let ((kind-icon-use-icons) (icon (plist-get plist :icon))) - (propertize "**" 'face `(:background ,bg-col) - 'display (apply #'svg-lib-icon icon nil - :foreground col :background bg-col - kind-icon-default-style)) - (propertize - (cadr map) 'face - `(:weight bold :foreground ,col :background ,bg-col))))) + ;; icon: always 2x1, half-space on each side + (propertize (concat + pad-left + (propertize "*" ; pretend 2 char-wide icon is only 1 + 'display (apply #'svg-lib-icon icon nil + :foreground col + :background bg-col + kind-icon-default-style)) + pad-right) 'face `(:background ,bg-col)) + ;; text, 1 or 2 chars, centered with full or half space on each side + (let* ((txt (truncate-string-to-width (cadr map) 2)) + (len (length txt)) + (txt-disp (if (eq len 2) + (concat pad-left (propertize "_" 'display txt) pad-right) + (concat " " txt " ")))) + (propertize txt-disp 'face + `(:weight bold :foreground ,col :background ,bg-col)))))) (plist-put plist :display-icon disp) disp)))) @@ -209,9 +256,11 @@ and its result used as the affixation suffix, first setting the (add-face-text-property 0 (length suffix) 'completions-annotations 'append suffix) (if-let ((kind (funcall kind-func cand)) - (badge (kind-icon-badge kind))) + (badge (kind-icon-formatted kind))) (list cand badge suffix) - (list cand kind-icon--unknown suffix)))) + (list cand + (propertize "??" 'face '(:weight bold :background "red")) + suffix)))) candidates))) (defvar-local kind-icon--orig-completion-function nil