├── company-box.png ├── images ├── Class.png ├── Event.png ├── Field.png ├── Folder.png ├── Method.png ├── Misc.png ├── String.png ├── Constant.png ├── Document.png ├── EnumItem.png ├── Keyword.png ├── Property.png ├── Template.png ├── Enumerator.png ├── Interface.png ├── Namespace.png ├── idea │ ├── advice.png │ ├── class.png │ ├── enum.png │ ├── field.png │ ├── method.png │ ├── misc.png │ ├── module.png │ ├── ppFile.png │ ├── static.png │ ├── package.png │ ├── property.png │ ├── readonly.png │ ├── snippet.png │ ├── textArea.png │ ├── variable.png │ ├── interface.png │ ├── parameter.png │ ├── textField.png │ └── sourceFolder.png ├── ColorPalette.png ├── LocalVariable.png ├── eclipse │ ├── class.png │ ├── enum.png │ ├── field.png │ ├── text.png │ ├── value.png │ ├── boolean.png │ ├── class@2x.png │ ├── constant.png │ ├── enum@2x.png │ ├── field@2x.png │ ├── function.png │ ├── keyword.png │ ├── method.png │ ├── module.png │ ├── number.png │ ├── package.png │ ├── property.png │ ├── snippet.png │ ├── text@2x.png │ ├── value@2x.png │ ├── variable.png │ ├── boolean@2x.png │ ├── interface.png │ ├── keyword@2x.png │ ├── method@2x.png │ ├── module@2x.png │ ├── namespace.png │ ├── number@2x.png │ ├── package@2x.png │ ├── reference.png │ ├── snippet@2x.png │ ├── constant@2x.png │ ├── constructor.png │ ├── function@2x.png │ ├── interface@2x.png │ ├── namespace@2x.png │ ├── property@2x.png │ ├── reference@2x.png │ ├── variable@2x.png │ └── constructor@2x.png └── netbeans │ ├── enum.png │ ├── file.png │ ├── text.png │ ├── unit.png │ ├── class.png │ ├── color.gif │ ├── empty.png │ ├── event.png │ ├── field.png │ ├── folder.gif │ ├── keyword.png │ ├── method.png │ ├── module.png │ ├── snippet.png │ ├── struct.png │ ├── value.png │ ├── attribute.png │ ├── constant.png │ ├── function.png │ ├── interface.png │ ├── operator.png │ ├── property.png │ ├── reference.png │ ├── variable.gif │ ├── constructor.png │ ├── enummember.png │ └── typeparameter.gif ├── README.md ├── company-box-doc.el ├── company-box-icons.el └── company-box.el /company-box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/company-box.png -------------------------------------------------------------------------------- /images/Class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/Class.png -------------------------------------------------------------------------------- /images/Event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/Event.png -------------------------------------------------------------------------------- /images/Field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/Field.png -------------------------------------------------------------------------------- /images/Folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/Folder.png -------------------------------------------------------------------------------- /images/Method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/Method.png -------------------------------------------------------------------------------- /images/Misc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/Misc.png -------------------------------------------------------------------------------- /images/String.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/String.png -------------------------------------------------------------------------------- /images/Constant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/Constant.png -------------------------------------------------------------------------------- /images/Document.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/Document.png -------------------------------------------------------------------------------- /images/EnumItem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/EnumItem.png -------------------------------------------------------------------------------- /images/Keyword.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/Keyword.png -------------------------------------------------------------------------------- /images/Property.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/Property.png -------------------------------------------------------------------------------- /images/Template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/Template.png -------------------------------------------------------------------------------- /images/Enumerator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/Enumerator.png -------------------------------------------------------------------------------- /images/Interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/Interface.png -------------------------------------------------------------------------------- /images/Namespace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/Namespace.png -------------------------------------------------------------------------------- /images/idea/advice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/advice.png -------------------------------------------------------------------------------- /images/idea/class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/class.png -------------------------------------------------------------------------------- /images/idea/enum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/enum.png -------------------------------------------------------------------------------- /images/idea/field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/field.png -------------------------------------------------------------------------------- /images/idea/method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/method.png -------------------------------------------------------------------------------- /images/idea/misc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/misc.png -------------------------------------------------------------------------------- /images/idea/module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/module.png -------------------------------------------------------------------------------- /images/idea/ppFile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/ppFile.png -------------------------------------------------------------------------------- /images/idea/static.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/static.png -------------------------------------------------------------------------------- /images/ColorPalette.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/ColorPalette.png -------------------------------------------------------------------------------- /images/LocalVariable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/LocalVariable.png -------------------------------------------------------------------------------- /images/eclipse/class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/class.png -------------------------------------------------------------------------------- /images/eclipse/enum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/enum.png -------------------------------------------------------------------------------- /images/eclipse/field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/field.png -------------------------------------------------------------------------------- /images/eclipse/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/text.png -------------------------------------------------------------------------------- /images/eclipse/value.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/value.png -------------------------------------------------------------------------------- /images/idea/package.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/package.png -------------------------------------------------------------------------------- /images/idea/property.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/property.png -------------------------------------------------------------------------------- /images/idea/readonly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/readonly.png -------------------------------------------------------------------------------- /images/idea/snippet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/snippet.png -------------------------------------------------------------------------------- /images/idea/textArea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/textArea.png -------------------------------------------------------------------------------- /images/idea/variable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/variable.png -------------------------------------------------------------------------------- /images/netbeans/enum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/enum.png -------------------------------------------------------------------------------- /images/netbeans/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/file.png -------------------------------------------------------------------------------- /images/netbeans/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/text.png -------------------------------------------------------------------------------- /images/netbeans/unit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/unit.png -------------------------------------------------------------------------------- /images/eclipse/boolean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/boolean.png -------------------------------------------------------------------------------- /images/eclipse/class@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/class@2x.png -------------------------------------------------------------------------------- /images/eclipse/constant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/constant.png -------------------------------------------------------------------------------- /images/eclipse/enum@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/enum@2x.png -------------------------------------------------------------------------------- /images/eclipse/field@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/field@2x.png -------------------------------------------------------------------------------- /images/eclipse/function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/function.png -------------------------------------------------------------------------------- /images/eclipse/keyword.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/keyword.png -------------------------------------------------------------------------------- /images/eclipse/method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/method.png -------------------------------------------------------------------------------- /images/eclipse/module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/module.png -------------------------------------------------------------------------------- /images/eclipse/number.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/number.png -------------------------------------------------------------------------------- /images/eclipse/package.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/package.png -------------------------------------------------------------------------------- /images/eclipse/property.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/property.png -------------------------------------------------------------------------------- /images/eclipse/snippet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/snippet.png -------------------------------------------------------------------------------- /images/eclipse/text@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/text@2x.png -------------------------------------------------------------------------------- /images/eclipse/value@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/value@2x.png -------------------------------------------------------------------------------- /images/eclipse/variable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/variable.png -------------------------------------------------------------------------------- /images/idea/interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/interface.png -------------------------------------------------------------------------------- /images/idea/parameter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/parameter.png -------------------------------------------------------------------------------- /images/idea/textField.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/textField.png -------------------------------------------------------------------------------- /images/netbeans/class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/class.png -------------------------------------------------------------------------------- /images/netbeans/color.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/color.gif -------------------------------------------------------------------------------- /images/netbeans/empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/empty.png -------------------------------------------------------------------------------- /images/netbeans/event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/event.png -------------------------------------------------------------------------------- /images/netbeans/field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/field.png -------------------------------------------------------------------------------- /images/netbeans/folder.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/folder.gif -------------------------------------------------------------------------------- /images/netbeans/keyword.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/keyword.png -------------------------------------------------------------------------------- /images/netbeans/method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/method.png -------------------------------------------------------------------------------- /images/netbeans/module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/module.png -------------------------------------------------------------------------------- /images/netbeans/snippet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/snippet.png -------------------------------------------------------------------------------- /images/netbeans/struct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/struct.png -------------------------------------------------------------------------------- /images/netbeans/value.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/value.png -------------------------------------------------------------------------------- /images/eclipse/boolean@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/boolean@2x.png -------------------------------------------------------------------------------- /images/eclipse/interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/interface.png -------------------------------------------------------------------------------- /images/eclipse/keyword@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/keyword@2x.png -------------------------------------------------------------------------------- /images/eclipse/method@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/method@2x.png -------------------------------------------------------------------------------- /images/eclipse/module@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/module@2x.png -------------------------------------------------------------------------------- /images/eclipse/namespace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/namespace.png -------------------------------------------------------------------------------- /images/eclipse/number@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/number@2x.png -------------------------------------------------------------------------------- /images/eclipse/package@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/package@2x.png -------------------------------------------------------------------------------- /images/eclipse/reference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/reference.png -------------------------------------------------------------------------------- /images/eclipse/snippet@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/snippet@2x.png -------------------------------------------------------------------------------- /images/idea/sourceFolder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/idea/sourceFolder.png -------------------------------------------------------------------------------- /images/netbeans/attribute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/attribute.png -------------------------------------------------------------------------------- /images/netbeans/constant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/constant.png -------------------------------------------------------------------------------- /images/netbeans/function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/function.png -------------------------------------------------------------------------------- /images/netbeans/interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/interface.png -------------------------------------------------------------------------------- /images/netbeans/operator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/operator.png -------------------------------------------------------------------------------- /images/netbeans/property.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/property.png -------------------------------------------------------------------------------- /images/netbeans/reference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/reference.png -------------------------------------------------------------------------------- /images/netbeans/variable.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/variable.gif -------------------------------------------------------------------------------- /images/eclipse/constant@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/constant@2x.png -------------------------------------------------------------------------------- /images/eclipse/constructor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/constructor.png -------------------------------------------------------------------------------- /images/eclipse/function@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/function@2x.png -------------------------------------------------------------------------------- /images/eclipse/interface@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/interface@2x.png -------------------------------------------------------------------------------- /images/eclipse/namespace@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/namespace@2x.png -------------------------------------------------------------------------------- /images/eclipse/property@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/property@2x.png -------------------------------------------------------------------------------- /images/eclipse/reference@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/reference@2x.png -------------------------------------------------------------------------------- /images/eclipse/variable@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/variable@2x.png -------------------------------------------------------------------------------- /images/netbeans/constructor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/constructor.png -------------------------------------------------------------------------------- /images/netbeans/enummember.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/enummember.png -------------------------------------------------------------------------------- /images/eclipse/constructor@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/eclipse/constructor@2x.png -------------------------------------------------------------------------------- /images/netbeans/typeparameter.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiencs/company-box/HEAD/images/netbeans/typeparameter.gif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # company-box 3 | [![MELPA](http://melpa.org/packages/company-box-badge.svg)](http://melpa.org/#/company-box) 4 | 5 | A company front-end with icons. 6 | 7 | ![company-box](company-box.png) 8 | 9 | Differences with the built-in front-end: 10 | - Differents colors for differents backends. 11 | - Icons associated to functions/variables/.. and their backends 12 | - Display candidate's documentation (support `quickhelp-string`) 13 | - Not limited by the current window size, buffer's text properties, .. (it's better than you might think) 14 | 15 | This package requires emacs 26. 16 | Also, not compatible with emacs in a tty. 17 | 18 | ### Installation 19 | ``` el 20 | ;; With use-package: 21 | (use-package company-box 22 | :hook (company-mode . company-box-mode)) 23 | 24 | ;; Or: 25 | (require 'company-box) 26 | (add-hook 'company-mode-hook 'company-box-mode) 27 | ``` 28 | 29 | To customize: 30 | `M-x customize-group [RET] company-box [RET]` 31 | 32 | ### Backends colors 33 | 34 | See the docstring of the variable `company-box-backends-colors`: 35 | `C-h v company-box-backends-colors` 36 | 37 | ### Themes 38 | 39 | You can select different themes with `company-box-icons-alist` 40 | 41 | ### Icons 42 | 43 | See the variable `company-box-icons-functions` 44 | 45 | For now, there are customs icons for 4 backends only: `company-lsp`, `company-elisp`, `company-yasnippet` and `company-php`. 46 | You can customize their icons with the variables: 47 | `company-box-icons-lsp`, `company-box-icons-elisp`, `company-box-icons-yasnippet` and `company-box-icons-acphp`. 48 | 49 | Notes: 50 | By default, images are used to display icons. 51 | You can also use [font icons](https://github.com/sebastiencs/company-box/wiki/icons) 52 | With images, you can't change icons colors 53 | 54 | ### Top margin 55 | 56 | You can position the frame downwards by setting the variable `company-box-frame-top-margin` to a positive number. This is useful if your base code/text has an enlarged line height, and company box is intruding into the line above. It's also useful, if you're using copilot and want to see a few lines of suggested code unobscured by the company box. See [PR #205](https://github.com/sebastiencs/company-box/pull/205) for details. 57 | 58 | You can set the top margin mode-dependent via mode hooks, if you want. E.g. in Doom Emacs: 59 | 60 | ``` el 61 | (use-package! company-box 62 | :defer t 63 | :config 64 | (setq-hook! 'prog-mode-hook 65 | company-box-frame-top-margin 20) 66 | (setq-hook! 'text-mode-hook 67 | company-box-frame-top-margin 75) 68 | ) 69 | ``` 70 | -------------------------------------------------------------------------------- /company-box-doc.el: -------------------------------------------------------------------------------- 1 | ;;; company-box-doc.el --- Company front-end -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2018 Sebastien Chapuis 4 | 5 | ;; Author: Sebastien Chapuis 6 | ;; URL: https://github.com/sebastiencs/company-box 7 | 8 | ;;; License 9 | ;; 10 | ;; This program is free software; you can redistribute it and/or modify 11 | ;; it under the terms of the GNU General Public License as published by 12 | ;; the Free Software Foundation; either version 3, or (at your option) 13 | ;; any later version. 14 | 15 | ;; This program is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with this program; see the file COPYING. If not, write to 22 | ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth 23 | ;; Floor, Boston, MA 02110-1301, USA. 24 | 25 | ;;; Commentary: 26 | ;; 27 | ;; Display candidate's documentation in another frame 28 | 29 | ;;; Code: 30 | 31 | (require 'dash) 32 | (require 'company) 33 | (require 'frame-local) 34 | (require 'cl-macs) 35 | (require 'subr-x) 36 | 37 | (defgroup company-box-doc nil 38 | "Display documentation popups alongside company-box" 39 | :group 'company) 40 | 41 | (defcustom company-box-doc-enable t 42 | "Enable company-box-doc by default." 43 | :type 'boolean 44 | :safe #'booleanp 45 | :group 'company-box-doc) 46 | 47 | (defcustom company-box-doc-delay 0.5 48 | "The number of seconds to wait before displaying the popup." 49 | :type 'number 50 | :group 'company-box-doc) 51 | 52 | (defcustom company-box-doc-no-wrap nil 53 | "Specify whether or not to wrap the documentation box at the edge of 54 | the Emacs frame." 55 | :type 'boolean 56 | :group 'company-box-doc) 57 | 58 | (defvar company-box-doc-frame-parameters 59 | '((internal-border-width . 10)) 60 | "Frame parameters to use on the doc frame. 61 | `company-box-frame-parameters' is then append to this variable.") 62 | 63 | (declare-function company-box--get-frame 'company-box) 64 | (declare-function company-box--set-frame 'company-box) 65 | (declare-function company-box--get-buffer 'company-box) 66 | (declare-function company-box--make-frame 'company-box) 67 | 68 | (defvar company-box-frame-parameters) 69 | (defvar company-box--bottom) 70 | (defvar company-box-scrollbar) 71 | 72 | (defvar-local company-box-doc--timer nil) 73 | 74 | (defun company-box-doc--fetch-doc-buffer (candidate) 75 | (let ((inhibit-message t) (message-log-max nil)) 76 | (--> (while-no-input 77 | (-some-> (company-call-backend 'doc-buffer candidate) 78 | (get-buffer))) 79 | (if (eq t it) nil it)))) 80 | 81 | (defun company-box-doc--set-frame-position (frame) 82 | (-let* ((box-position (frame-position (company-box--get-frame))) 83 | (box-width (frame-pixel-width (company-box--get-frame))) 84 | (window (frame-root-window frame)) 85 | (frame-resize-pixelwise t) 86 | ((width . height) 87 | (if company-box-doc-no-wrap 88 | (window-text-pixel-size window nil nil 10000 10000) 89 | (window-text-pixel-size 90 | window nil nil 91 | ;; Use the widest space available (left or right of the box frame) 92 | (let ((space-right (- (frame-native-width) (+ 40 (car box-position) box-width))) 93 | (space-left (- (car box-position) 40))) 94 | (if (< space-right space-left) space-left space-right)) 95 | (- (frame-native-height) 40)))) 96 | (bottom (+ company-box--bottom (window-pixel-top) (frame-border-width))) 97 | (x (+ (car box-position) box-width (/ (frame-char-width) 2))) 98 | (y (cdr box-position)) 99 | (y (if (> (+ y height 20) bottom) 100 | (- y (- (+ y height) bottom) 20) 101 | y)) 102 | (space-right (- (frame-pixel-width) x)) 103 | (space-left (car box-position)) 104 | (x (or (let ((border (* (or (alist-get 'internal-border-width company-box-doc-frame-parameters) 0) 105 | 2))) 106 | (and (> width space-right) 107 | (> space-left (+ width border (/ (frame-char-width) 2))) 108 | (- (car box-position) width border (/ (frame-char-width) 2)))) 109 | x))) 110 | (set-frame-position frame (max x 0) (max y 10)) 111 | (set-frame-size frame width height t))) 112 | 113 | (defun company-box-doc--make-buffer (object) 114 | (let* ((buffer-list-update-hook nil) 115 | (inhibit-modification-hooks t) 116 | (string (cond ((stringp object) object) 117 | ((bufferp object) (with-current-buffer object (buffer-string)))))) 118 | (when (and string (> (length (string-trim string)) 0)) 119 | (with-current-buffer (company-box--get-buffer "doc") 120 | (erase-buffer) 121 | (insert string) 122 | (setq mode-line-format nil 123 | display-line-numbers nil 124 | header-line-format nil 125 | show-trailing-whitespace nil 126 | truncate-lines nil 127 | cursor-in-non-selected-windows nil) 128 | (current-buffer))))) 129 | 130 | (defun company-box-doc--make-frame (buffer) 131 | (let* ((company-box-frame-parameters 132 | (append company-box-doc-frame-parameters 133 | company-box-frame-parameters)) 134 | (frame (company-box--make-frame buffer))) 135 | ;; (set-face-background 'internal-border "white" frame) 136 | (set-frame-parameter frame 'name "") 137 | frame)) 138 | 139 | (defun company-box-doc--show (selection frame) 140 | (cl-letf (((symbol-function 'completing-read) #'company-box-completing-read) 141 | (window-configuration-change-hook nil) 142 | (inhibit-redisplay t) 143 | (display-buffer-alist nil) 144 | (buffer-list-update-hook nil)) 145 | (-when-let* ((valid-state (and (eq (selected-frame) frame) 146 | company-box--bottom 147 | company-selection 148 | (company-box--get-frame) 149 | (frame-visible-p (company-box--get-frame)))) 150 | (candidate (nth selection company-candidates)) 151 | (doc (or (company-call-backend 'quickhelp-string candidate) 152 | (company-box-doc--fetch-doc-buffer candidate))) 153 | (doc (company-box-doc--make-buffer doc))) 154 | (unless (frame-live-p (frame-local-getq company-box-doc-frame)) 155 | (frame-local-setq company-box-doc-frame (company-box-doc--make-frame doc))) 156 | (company-box-doc--set-frame-position (frame-local-getq company-box-doc-frame)) 157 | (unless (frame-visible-p (frame-local-getq company-box-doc-frame)) 158 | (make-frame-visible (frame-local-getq company-box-doc-frame)))))) 159 | 160 | (defun company-box-completing-read (_prompt candidates &rest _) 161 | "`cider', and probably other libraries, prompt the user to 162 | resolve ambiguous documentation requests. Instead of failing we 163 | just grab the first candidate and press forward." 164 | (car candidates)) 165 | 166 | (defun company-box-doc (selection frame) 167 | (when company-box-doc-enable 168 | (company-box-doc--hide frame) 169 | (when (timerp company-box-doc--timer) 170 | (cancel-timer company-box-doc--timer)) 171 | (setq company-box-doc--timer 172 | (run-with-timer 173 | company-box-doc-delay nil 174 | (lambda nil 175 | (company-box-doc--show selection frame) 176 | (company-ensure-emulation-alist)))))) 177 | 178 | (defun company-box-doc--hide (frame) 179 | (let ((frame (frame-local-getq company-box-doc-frame frame))) 180 | (and (frame-live-p frame) 181 | (make-frame-invisible frame)))) 182 | 183 | (defun company-box-doc--delete-frame () 184 | "Delete the child frame if it exists." 185 | (-when-let (frame (frame-local-getq company-box-doc-frame)) 186 | (and (frame-live-p frame) 187 | (delete-frame frame)) 188 | (frame-local-setq company-box-doc-frame nil))) 189 | 190 | (defun company-box-doc-manually () 191 | (interactive) 192 | (company-box-doc--show company-selection (or (frame-parent) (selected-frame)))) 193 | 194 | (define-key company-active-map [remap company-show-doc-buffer] 'company-box-doc-manually) 195 | 196 | (provide 'company-box-doc) 197 | ;;; company-box-doc.el ends here 198 | -------------------------------------------------------------------------------- /company-box-icons.el: -------------------------------------------------------------------------------- 1 | ;;; company-box-icons.el --- Company front-end -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2017 Sebastien Chapuis 4 | 5 | ;; Author: Sebastien Chapuis 6 | ;; URL: https://github.com/sebastiencs/company-box 7 | 8 | ;;; License 9 | ;; 10 | ;; This program is free software; you can redistribute it and/or modify 11 | ;; it under the terms of the GNU General Public License as published by 12 | ;; the Free Software Foundation; either version 3, or (at your option) 13 | ;; any later version. 14 | 15 | ;; This program is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with this program; see the file COPYING. If not, write to 22 | ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth 23 | ;; Floor, Boston, MA 02110-1301, USA. 24 | 25 | ;;; Commentary: 26 | ;; 27 | ;; Icons for company-box 28 | 29 | ;;; Code: 30 | 31 | (require 'dash) 32 | 33 | (eval-when-compile 34 | (require 'find-func) 35 | (require 'subr-x) 36 | (defconst company-box-icons-dir 37 | (->> (find-library-name "company-box") 38 | (file-name-directory) 39 | (expand-file-name "images") 40 | (file-name-as-directory))) 41 | (defconst company-box--have-imagemagick (image-type-available-p 'imagemagick) 42 | "Emacs might not be compiled with imagemagick.") 43 | (defun company-box-icons-image (file) 44 | (let* ((extension (intern (upcase (or (file-name-extension file) "")))) 45 | (use-magick (and company-box--have-imagemagick 46 | (not (member extension imagemagick-types-inhibit)) 47 | (member extension imagemagick-enabled-types)))) 48 | `(image :type ,(if use-magick 'imagemagick 'png) 49 | :file ,(concat company-box-icons-dir file) 50 | :ascent center)))) 51 | 52 | (defvar company-box-icons-icons-in-terminal 53 | '((Unknown fa_question_circle) 54 | (Text . fa_text_height) ;; Text 55 | (Method . (fa_tags :face font-lock-function-name-face)) ;; Method 56 | (Function . (fa_tag :face font-lock-function-name-face)) ;; Function 57 | (Constructor . (fa_tag :face font-lock-function-name-face)) ;; Constructor 58 | (Field . (fa_cog :foreground "#FF9800")) ;; Field 59 | (Variable . (fa_cog :foreground "#FF9800")) ;; Variable 60 | (Class . (fa_cube :foreground "#7C4DFF")) ;; Class 61 | (Interface . (fa_cube :foreground "#7C4DFF")) ;; Interface 62 | (Module . (fa_cube :foreground "#7C4DFF")) ;; Module 63 | (Property . (fa_cog :foreground "#FF9800")) ;; Property 64 | (Unit . md_settings_system_daydream) ;; Unit 65 | (Value . (fa_cog :foreground "#FF9800")) ;; Value 66 | (Enum . (md_storage :face font-lock-type-face)) ;; Enum 67 | (Keyword . (md_closed_caption :foreground "#009688")) ;; Keyword 68 | (Snippet . md_closed_caption) ;; Snippet 69 | (Color . (md_color_lens :face font-lock-doc-face)) ;; Color 70 | (File . fa_file_text_o) ;; File 71 | (Reference . md_refresh) ;; Reference 72 | (Folder . fa_folder_open) ;; Folder 73 | (EnumMember . (md_closed_caption :foreground "#009688")) ;; EnumMember 74 | (Constant . (fa_square :face font-lock-constant-face)) ;; Constant 75 | (Struct . (fa_cube :face font-lock-type-face)) ;; Struct 76 | (Event . fa_calendar) ;; Event 77 | (Operator . fa_square_o) ;; Operator 78 | (TypeParameter . fa_arrows) 79 | (Template . fa_bookmark)) ;; TypeParameter 80 | ) 81 | 82 | (defvar company-box-icons-eclipse 83 | (eval-when-compile 84 | `((Unknown . ,(company-box-icons-image "Namespace.png")) 85 | (Text . ,(company-box-icons-image "eclipse/text.png")) 86 | (Method . ,(company-box-icons-image "eclipse/method.png")) 87 | (Function . ,(company-box-icons-image "eclipse/function.png")) 88 | (Constructor . ,(company-box-icons-image "eclipse/constructor.png")) 89 | (Field . ,(company-box-icons-image "eclipse/field.png")) 90 | (Variable . ,(company-box-icons-image "eclipse/variable.png")) 91 | (Class . ,(company-box-icons-image "eclipse/class.png")) 92 | (Interface . ,(company-box-icons-image "eclipse/interface.png")) 93 | (Module . ,(company-box-icons-image "eclipse/module.png")) 94 | (Property . ,(company-box-icons-image "eclipse/property.png")) 95 | (Unit . ,(company-box-icons-image "eclipse/unit.png")) 96 | (Value . ,(company-box-icons-image "eclipse/value.png")) 97 | (Enum . ,(company-box-icons-image "eclipse/enum.png")) 98 | (Keyword . ,(company-box-icons-image "eclipse/keyword.png")) 99 | (Snippet . ,(company-box-icons-image "eclipse/snippet.png")) 100 | (Color . ,(company-box-icons-image "eclipse/color.png")) 101 | (File . ,(company-box-icons-image "eclipse/file.png")) 102 | (Reference . ,(company-box-icons-image "eclipse/reference.png")) 103 | (Folder . ,(company-box-icons-image "eclipse/folder.png")) 104 | (EnumMember . ,(company-box-icons-image "eclipse/enummember.png")) 105 | (Constant . ,(company-box-icons-image "eclipse/constant.png")) 106 | (Struct . ,(company-box-icons-image "eclipse/struct.png")) 107 | (Event . ,(company-box-icons-image "eclipse/event.png")) 108 | (Operator . ,(company-box-icons-image "eclipse/operator.png")) 109 | (TypeParameter . ,(company-box-icons-image "eclipse/typeparameter.png")) 110 | (Template . ,(company-box-icons-image "eclipse/template.png"))))) 111 | 112 | (defvar company-box-icons-netbeans 113 | (eval-when-compile 114 | `((Unknown . ,(company-box-icons-image "Namespace.png")) 115 | (Text . ,(company-box-icons-image "netbeans/text.png")) 116 | (Method . ,(company-box-icons-image "netbeans/method.png")) 117 | (Function . ,(company-box-icons-image "netbeans/function.png")) 118 | (Constructor . ,(company-box-icons-image "netbeans/constructor.png")) 119 | (Field . ,(company-box-icons-image "netbeans/field.png")) 120 | (Variable . ,(company-box-icons-image "netbeans/variable.gif")) 121 | (Class . ,(company-box-icons-image "netbeans/class.png")) 122 | (Interface . ,(company-box-icons-image "netbeans/interface.png")) 123 | (Module . ,(company-box-icons-image "netbeans/module.png")) 124 | (Property . ,(company-box-icons-image "netbeans/property.png")) 125 | (Unit . ,(company-box-icons-image "netbeans/unit.png")) 126 | (Value . ,(company-box-icons-image "netbeans/value.png")) 127 | (Enum . ,(company-box-icons-image "netbeans/enum.png")) 128 | (Keyword . ,(company-box-icons-image "netbeans/keyword.png")) 129 | (Snippet . ,(company-box-icons-image "netbeans/snippet.png")) 130 | (Color . ,(company-box-icons-image "netbeans/color.png")) 131 | (File . ,(company-box-icons-image "netbeans/file.png")) 132 | (Reference . ,(company-box-icons-image "netbeans/reference.png")) 133 | (Folder . ,(company-box-icons-image "netbeans/folder.png")) 134 | (EnumMember . ,(company-box-icons-image "netbeans/enummember.png")) 135 | (Constant . ,(company-box-icons-image "netbeans/constant.png")) 136 | (Struct . ,(company-box-icons-image "netbeans/struct.png")) 137 | (Event . ,(company-box-icons-image "netbeans/event.png")) 138 | (Operator . ,(company-box-icons-image "netbeans/operator.png")) 139 | (TypeParameter . ,(company-box-icons-image "netbeans/typeparameter.png")) 140 | (Template . ,(company-box-icons-image "netbeans/template.png"))))) 141 | 142 | (defvar company-box-icons-images 143 | (eval-when-compile 144 | `((Unknown . ,(company-box-icons-image "Namespace.png")) 145 | (Text . ,(company-box-icons-image "String.png")) 146 | (Method . ,(company-box-icons-image "Method.png")) 147 | (Function . ,(company-box-icons-image "Method.png")) 148 | (Constructor . ,(company-box-icons-image "Method.png")) 149 | (Field . ,(company-box-icons-image "Field.png")) 150 | (Variable . ,(company-box-icons-image "Field.png")) 151 | (Class . ,(company-box-icons-image "Class.png")) 152 | (Interface . ,(company-box-icons-image "Interface.png")) 153 | (Module . ,(company-box-icons-image "Namespace.png")) 154 | (Property . ,(company-box-icons-image "Property.png")) 155 | (Unit . ,(company-box-icons-image "Misc.png")) 156 | (Value . ,(company-box-icons-image "EnumItem.png")) 157 | (Enum . ,(company-box-icons-image "Enumerator.png")) 158 | (Keyword . ,(company-box-icons-image "Keyword.png")) 159 | (Snippet . ,(company-box-icons-image "String.png")) 160 | (Color . ,(company-box-icons-image "ColorPalette.png")) 161 | (File . ,(company-box-icons-image "Document.png")) 162 | (Reference . ,(company-box-icons-image "Misc.png")) 163 | (Folder . ,(company-box-icons-image "Folder.png")) 164 | (EnumMember . ,(company-box-icons-image "EnumItem.png")) 165 | (Constant . ,(company-box-icons-image "Constant.png")) 166 | (Struct . ,(company-box-icons-image "Class.png")) 167 | (Event . ,(company-box-icons-image "Event.png")) 168 | (Operator . ,(company-box-icons-image "Misc.png")) 169 | (TypeParameter . ,(company-box-icons-image "Class.png")) 170 | (Template . ,(company-box-icons-image "Template.png"))))) 171 | 172 | (defvar company-box-icons-idea 173 | (eval-when-compile 174 | `((Unknown . ,(company-box-icons-image "idea/package.png")) 175 | ;; (Text . ,(company-box-icons-image "idea/misc.png")) 176 | (Method . ,(company-box-icons-image "idea/method.png")) 177 | (Function . ,(company-box-icons-image "idea/method.png")) 178 | (Constructor . ,(company-box-icons-image "idea/method.png")) 179 | (Field . ,(company-box-icons-image "idea/field.png")) 180 | (Variable . ,(company-box-icons-image "idea/field.png")) 181 | (Class . ,(company-box-icons-image "idea/class.png")) 182 | (Interface . ,(company-box-icons-image "idea/interface.png")) 183 | (Module . ,(company-box-icons-image "idea/package.png")) 184 | (Property . ,(company-box-icons-image "idea/property.png")) 185 | ;; (Unit . ,(company-box-icons-image "idea/misc.png")) 186 | (Value . ,(company-box-icons-image "idea/field.png")) 187 | (Enum . ,(company-box-icons-image "idea/enum.png")) 188 | ;; (Keyword . ,(company-box-icons-image "idea/misc.png")) 189 | (Snippet . ,(company-box-icons-image "idea/snippet.png")) 190 | ;; (Color . ,(company-box-icons-image "idea/misc.png")) 191 | (File . ,(company-box-icons-image "idea/ppFile.png")) 192 | (Reference . ,(company-box-icons-image "idea/misc.png")) 193 | (Folder . ,(company-box-icons-image "idea/ppFile.png")) 194 | (EnumMember . ,(company-box-icons-image "idea/enum.png")) 195 | (Constant . ,(company-box-icons-image "idea/field.png")) 196 | (Struct . ,(company-box-icons-image "idea/class.png")) 197 | (Event . ,(company-box-icons-image "Event.png")) 198 | ;; (Operator . ,(company-box-icons-image "Misc.png")) 199 | (TypeParameter . ,(company-box-icons-image "Class.png")) 200 | (Template . ,(company-box-icons-image "Template.png"))))) 201 | 202 | (declare-function all-the-icons-faicon "ext:all-the-icons") 203 | (declare-function all-the-icons-material "ext:all-the-icons") 204 | (declare-function all-the-icons-octicon "ext:all-the-icons") 205 | 206 | (when (require 'all-the-icons nil t) 207 | (defvar company-box-icons-all-the-icons 208 | `((Unknown . ,(all-the-icons-faicon "code")) 209 | (Text . ,(all-the-icons-material "text_format")) 210 | (Method . ,(all-the-icons-faicon "cube")) 211 | (Function . ,(all-the-icons-faicon "cube")) 212 | (Constructor . ,(all-the-icons-faicon "cube")) 213 | (Field . ,(all-the-icons-faicon "tag")) 214 | (Variable . ,(all-the-icons-faicon "tag")) 215 | (Class . ,(all-the-icons-faicon "cogs")) 216 | (Interface . ,(all-the-icons-faicon "italic")) 217 | (Module . ,(all-the-icons-faicon "code")) 218 | (Property . ,(all-the-icons-faicon "wrench")) 219 | (Unit . ,(all-the-icons-material "streetview")) 220 | (Value . ,(all-the-icons-faicon "tag")) 221 | (Enum . ,(all-the-icons-material "library_books")) 222 | (Keyword . ,(all-the-icons-material "vpn_key")) 223 | (Snippet . ,(all-the-icons-faicon "expand")) 224 | (Color . ,(all-the-icons-material "palette")) 225 | (File . ,(all-the-icons-faicon "file")) 226 | (Reference . ,(all-the-icons-material "streetview")) 227 | (Folder . ,(all-the-icons-faicon "folder-open")) 228 | (EnumMember . ,(all-the-icons-faicon "book")) 229 | (Constant . ,(all-the-icons-faicon "bars")) 230 | (Struct . ,(all-the-icons-faicon "cogs")) 231 | (Event . ,(all-the-icons-faicon "bolt")) 232 | (Operator . ,(all-the-icons-material "streetview")) 233 | (TypeParameter . ,(all-the-icons-faicon "cogs")) 234 | (Template . ,(all-the-icons-material "settings_ethernet"))))) 235 | 236 | (defcustom company-box-icons-alist 'company-box-icons-images 237 | "Rendering method for icons. 238 | 239 | - Images 240 | - idea, from idea editors 241 | - netbeans, from netbeans editor 242 | - eclipse, from eclipse editor 243 | - all-the-icons [1] 244 | - icons-in-terminal [2] 245 | 246 | Changing colors of icons only works with `all-the-icons' and 247 | `icons-in-terminal'. Colors with others methods are taken from 248 | the image. 249 | 250 | [1] https://github.com/domtronn/all-the-icons.el 251 | [2] https://github.com/sebastiencs/icons-in-terminal 252 | ." 253 | :type '(choice (const :tag "images" company-box-icons-images) 254 | (const :tag "idea" company-box-icons-idea) 255 | (const :tag "netbeans" company-box-icons-netbeans) 256 | (const :tag "eclipse" company-box-icons-eclipse) 257 | (const :tag "all-the-icons" company-box-icons-all-the-icons) 258 | (const :tag "icons-in-terminal" company-box-icons-icons-in-terminal)) 259 | :group 'company-box) 260 | 261 | (defconst company-box-icons--lsp-alist 262 | '((1 . Text) 263 | (2 . Method) 264 | (3 . Function) 265 | (4 . Constructor) 266 | (5 . Field) 267 | (6 . Variable) 268 | (7 . Class) 269 | (8 . Interface) 270 | (9 . Module) 271 | (10 . Property) 272 | (11 . Unit) 273 | (12 . Value) 274 | (13 . Enum) 275 | (14 . Keyword) 276 | (15 . Snippet) 277 | (16 . Color) 278 | (17 . File) 279 | (18 . Reference) 280 | (19 . Folder) 281 | (20 . EnumMember) 282 | (21 . Constant) 283 | (22 . Struct) 284 | (23 . Event) 285 | (24 . Operator) 286 | (25 . TypeParameter)) 287 | "List of Icons to use with LSP candidates. 288 | 289 | Each element have the form: 290 | (KIND . ICON-TYPE) 291 | 292 | Where KIND correspond to a number, the CompletionItemKind from the LSP [1] 293 | 294 | See `company-box-icons-images' or `company-box-icons-all-the-icons' for 295 | the ICON-TYPEs 296 | 297 | [1] https://github.com/Microsoft/language-server-protocol/blob/gh-pages/\ 298 | specification.md#completion-request-leftwards_arrow_with_hook.") 299 | 300 | (defconst company-box-icons--eglot-alist 301 | company-box-icons--lsp-alist) 302 | 303 | (defun company-box-icons--lsp (candidate) 304 | (-when-let* ((lsp-item (get-text-property 0 'lsp-completion-item candidate)) 305 | (kind-num (and (fboundp 'lsp-get) (lsp-get lsp-item :kind)))) 306 | (alist-get kind-num company-box-icons--lsp-alist))) 307 | 308 | (defun company-box-icons--eglot (candidate) 309 | (-when-let* ((eglot-item (get-text-property 0 'eglot--lsp-item candidate)) 310 | (kind-num (plist-get eglot-item :kind))) 311 | (alist-get kind-num company-box-icons--eglot-alist))) 312 | 313 | (defconst company-box-icons--php-alist 314 | '(("t" . Interface) 315 | ("c" . Class) 316 | ("m" . Method) 317 | ("f" . Function) 318 | ("p" . Property) 319 | ("d" . Constant) 320 | ("v" . Variable) 321 | ("i" . Interface) 322 | ("n" . Module) 323 | ("T" . Template)) 324 | "List of icon types to use with PHP candidates.") 325 | 326 | (defun company-box-icons--acphp (candidate) 327 | (when (derived-mode-p 'php-mode) 328 | (-> (get-text-property 0 'ac-php-tag-type candidate) 329 | (alist-get company-box-icons--php-alist)))) 330 | 331 | (defconst company-box-icons--cider-alist 332 | '(("special-form" . Operator) 333 | ("function" . Function) 334 | ("method" . Method) 335 | ("macro" . Template) 336 | ("class" . Class) 337 | ("import" . Module) 338 | ("field" . Field) 339 | ("keyword" . Keyword) 340 | ("local" . Variable) 341 | ("var" . Variable) 342 | ("namespace" . Unit) 343 | ("protocol" . Interface) 344 | ("protocol-function" . Property) 345 | ("record" . Constructor) 346 | ("static-field" . Field) 347 | ("static-method" . Method) 348 | ("type" . TypeParameter)) 349 | "List of icon types to use with CIDER candidates. 350 | Check out `cider-completion-annotations-alist'.") 351 | 352 | (defun company-box-icons--cider (candidate) 353 | (when (or (derived-mode-p 'clojure-mode) (derived-mode-p 'cider-repl-mode)) 354 | (-> (get-text-property 0 'type candidate) 355 | (alist-get company-box-icons--cider-alist nil nil 'equal)))) 356 | 357 | (defun company-box-icons--elisp (candidate) 358 | (when (derived-mode-p 'emacs-lisp-mode) 359 | (let ((sym (intern candidate))) 360 | ;; we even can move it to (predicate . kind) alist 361 | (cond ((fboundp sym) 'Function) 362 | ((featurep sym) 'Module) 363 | ((facep sym) 'Color) 364 | ((boundp sym) 'Variable) 365 | (t 'Unknown))))) 366 | 367 | (defun company-box-icons--yasnippet (candidate) 368 | (when (get-text-property 0 'yas-annotation candidate) 369 | 'Template)) 370 | 371 | (defun company-box-icons-resize (size &optional icons-images) 372 | "Set icons size in pixels." 373 | (interactive "nIcon size in pixels: ") 374 | (mapc (lambda (icon) 375 | (-> icon 376 | (plist-put :height size) 377 | (plist-put :width size))) 378 | (or icons-images company-box-icons-images))) 379 | 380 | (provide 'company-box-icons) 381 | ;;; company-box-icons.el ends here 382 | -------------------------------------------------------------------------------- /company-box.el: -------------------------------------------------------------------------------- 1 | ;;; company-box.el --- Company front-end with icons -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2018 Sebastien Chapuis 4 | 5 | ;; Author: Sebastien Chapuis 6 | ;; URL: https://github.com/sebastiencs/company-box 7 | ;; Keywords: company, completion, front-end, convenience 8 | ;; Package-Requires: ((emacs "26.0.91") (dash "2.19.0") (company "0.9.6") (frame-local "0.0.1")) 9 | ;; Version: 0.0.1 10 | 11 | ;;; License 12 | ;; 13 | ;; This program is free software; you can redistribute it and/or modify 14 | ;; it under the terms of the GNU General Public License as published by 15 | ;; the Free Software Foundation; either version 3, or (at your option) 16 | ;; any later version. 17 | 18 | ;; This program is distributed in the hope that it will be useful, 19 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | ;; GNU General Public License for more details. 22 | 23 | ;; You should have received a copy of the GNU General Public License 24 | ;; along with this program; see the file COPYING. If not, write to 25 | ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth 26 | ;; Floor, Boston, MA 02110-1301, USA. 27 | 28 | 29 | ;;; Commentary: 30 | ;; 31 | ;; A company front-end 32 | ;; 33 | ;; Differences with the built-in front-end: 34 | ;; 35 | ;; - Different colors for differents backends. 36 | ;; - Icons associated to functions/variables/.. and their backends 37 | ;; - Display candidate's documentation (support quickhelp-string) 38 | ;; - Not limited by the current window size, buffer's text properties, .. 39 | ;; (it's better than you might think) 40 | ;; 41 | ;; This package requires Emacs 26. 42 | ;; Also, not compatible with Emacs in a tty. 43 | ;; 44 | ;; 45 | ;; Installation: 46 | ;; 47 | ;; With use-package: 48 | ;; (use-package company-box 49 | ;; :hook (company-mode . company-box-mode)) 50 | ;; Or: 51 | ;; (require 'company-box) 52 | ;; (add-hook 'company-mode-hook 'company-box-mode) 53 | ;; 54 | ;; To customize: 55 | ;; M-x customize-group [RET] company-box [RET] 56 | ;; 57 | ;; 58 | ;; For more informations, see the homepage: 59 | ;; https://github.com/sebastiencs/company-box 60 | 61 | ;;; Code: 62 | 63 | (require 'subr-x) 64 | (require 'dash) 65 | (require 'dash) 66 | (require 'company) 67 | (require 'company-box-icons) 68 | (require 'company-box-doc) 69 | (require 'frame-local) 70 | 71 | (defgroup company-box nil 72 | "Front-end for Company." 73 | :prefix "company-box-" 74 | :group 'company) 75 | 76 | (make-obsolete-variable 'company-box-max-candidates nil "") 77 | (make-obsolete-variable 'company-box-tooltip-minimum-width 'company-tooltip-minimum-width nil "") 78 | (make-obsolete-variable 'company-box-tooltip-maximum-width 'company-tooltip-maximum-width nil "") 79 | 80 | (defface company-box-candidate 81 | '((((background light)) :foreground "black") 82 | (t :foreground "white")) 83 | "Face used to color candidates." 84 | :group 'company-box) 85 | 86 | (defface company-box-annotation 87 | '((t :inherit company-tooltip-annotation)) 88 | "Face used to color annotations." 89 | :group 'company-box) 90 | 91 | (defface company-box-selection 92 | '((t :inherit company-tooltip-selection :extend t)) 93 | "Face used to color the selected candidate." 94 | :group 'company-box) 95 | 96 | (defface company-box-background 97 | '((t :inherit company-tooltip)) 98 | "Face used for frame background. 99 | Only the `background' color is used in this face." 100 | :group 'company-box) 101 | 102 | (defface company-box-scrollbar 103 | '((t :inherit company-tooltip-selection)) 104 | "Face used for the scrollbar. 105 | Only the `background' color is used in this face." 106 | :group 'company-box) 107 | 108 | (defface company-box-numbers 109 | '((t :inherit company-box-candidate)) 110 | "Face used for numbers when `company-show-quick-access' is used." 111 | :group 'company-box) 112 | 113 | (define-obsolete-face-alias 'company-box-annotation 'company-tooltip-annotation nil) 114 | (define-obsolete-face-alias 'company-box-selection 'company-tooltip-selection nil) 115 | (define-obsolete-face-alias 'company-box-background 'company-tooltip nil) 116 | (define-obsolete-face-alias 'company-box-candidate 'company-tooltip nil) 117 | (define-obsolete-face-alias 'company-box-numbers 'company-tooltip nil) 118 | 119 | (defcustom company-box-color-icon t 120 | "Whether or not to color icons. 121 | Note that icons from images cannot be colored." 122 | :type 'boolean 123 | :group 'company-box) 124 | 125 | (defcustom company-box-enable-icon t 126 | "Whether or not to display icons." 127 | :type 'boolean 128 | :group 'company-box) 129 | 130 | (defcustom company-box-max-candidates 100 131 | "Maximum number of candidates. 132 | A big number might slowndown the rendering. 133 | To change the number of _visible_ chandidates, see `company-tooltip-limit'" 134 | :type 'integer 135 | :group 'company-box) 136 | 137 | (defcustom company-box-tooltip-minimum-width 60 138 | "`company-box' minimum width." 139 | :type 'integer 140 | :group 'company-box) 141 | 142 | (defcustom company-box-tooltip-maximum-width 260 143 | "`company-box' maximum width." 144 | :type 'integer 145 | :group 'company-box) 146 | 147 | (defcustom company-box-show-single-candidate 'always 148 | "Whether or not to display the candidate if there is only one. 149 | `when-no-other-frontend' will display the candidate if no other front ends are 150 | detected." 151 | :type '(choice (const :tag "when-no-other-frontend" when-no-other-frontend) 152 | (const :tag "never" never) 153 | (const :tag "always" always)) 154 | :group 'company-box) 155 | 156 | (defcustom company-box-icons-functions 157 | '(company-box-icons--yasnippet company-box-icons--lsp company-box-icons--eglot company-box-icons--elisp company-box-icons--acphp company-box-icons--cider) 158 | "Functions to call on each candidate that should return an icon. 159 | The functions takes 1 parameter, the completion candidate. 160 | 161 | It should return an ICON or nil. 162 | An ICON can be either a SYMBOL, an IMAGE, a LIST, a STRING: 163 | 164 | - SYMBOL: It is the name of the icon (from `company-box--icons-in-terminal'). 165 | - IMAGE: An image descriptor [1] 166 | Example: \\='(image :type png :file \"/path/to/image.png\") 167 | - LIST: The list is then `apply' to `company-box--icons-in-terminal' 168 | function. Example: \\='(fa_icon :face some-face :foreground \"red\") 169 | - STRING: A simple string which is inserted, should be of length 1 170 | 171 | If a function returns nil, it call the next function in the list. 172 | If all functions returns nil, `company-box-icons-unknown' is used. 173 | 174 | [1] https://www.gnu.org/software/emacs/manual/html_node/elisp/Image-Descriptors.html" 175 | :type '(repeat symbol) 176 | :group 'company-box) 177 | 178 | (defcustom company-box-scrollbar t 179 | "Whether to draw the custom scrollbar or use default scrollbar. 180 | 181 | - t means uses the custom scrollbar 182 | - `inherit' uses same scrollbar than the current frame 183 | - `left' or `right' puts default scrollbars to the left or right 184 | - nil means draw no scrollbar." 185 | :type '(choice (const :tag "Custom scrollbar" t) 186 | (const :tag "Inherit scrollbar" inherit) 187 | (const :tag "Default scrollbar on left" left) 188 | (const :tag "Default scrollbar on right" right) 189 | (const :tag "No scrollbar" nil)) 190 | :group 'company-box) 191 | 192 | (defcustom company-box-frame-behavior 'default 193 | "Change frame position behavior." 194 | :type '(choice (const :tag "Default" default) 195 | (const :tag "Follow point as you type" point)) 196 | :group 'company-box) 197 | 198 | (defcustom company-box-icon-right-margin 0 199 | "Set the space between the icon and the candidate text. It can be an integer 200 | or a float number. For example, set `1' to add a space thats width is equal to a 201 | character (see `frame-char-width'), set `0.5' to get half width of a character." 202 | :type 'number 203 | :group 'company-box) 204 | 205 | (defcustom company-box-frame-top-margin 0 206 | "Set extra space above the top of the frame, in pixels. 207 | This is useful if the company box intrudes on the code/text above it. 208 | For example, set '70' if you're using copilot, to make sure 209 | the frame doesn't overlap with the first lines of copilot suggestions." 210 | :type 'number 211 | :group 'company-box) 212 | 213 | (make-obsolete-variable 'company-box-highlight-prefix nil nil) 214 | 215 | (defcustom company-box-highlight-prefix nil 216 | "[OBSOLETE] Highlight the prefix instead of common. 217 | Faces used are `company-tooltip-common' and `company-tooltip-common-selection' 218 | for both cases." 219 | :type 'boolean 220 | :safe #'booleanp 221 | :group 'company-box) 222 | 223 | (defvar company-box-backends-colors 224 | '((company-yasnippet . (:all "lime green" :selected (:background "lime green" :foreground "black")))) 225 | "List of colors to use for specific backends. 226 | 227 | Each element has the form (BACKEND . COLOR) 228 | 229 | BACKEND is the backend symbol for which the color applies 230 | COLOR can be a LIST or a STRING: 231 | 232 | - LIST: A property list with the following keys: 233 | `:candidate' : Color to use on the candidate 234 | `:annotation' : Color to use on the annotation 235 | `:icon' : Color to use on the icon. Does nothing if the 236 | icon is an image. 237 | `:all' : Replace (:candidate X :annotation X :icon X) 238 | For those 4 attributes, values can be a face, a plist 239 | or a string (a color) 240 | `:selected' : Color to use when the candidate is selected. 241 | It can be a plist or a face, not a string. 242 | It needs to define the background and foreground colors 243 | 244 | - STRING: A color string which is used everywhere 245 | (similar to (:all \"red\")) 246 | 247 | Examples: 248 | 249 | \\='((company-yasnippet . (:candidate \"yellow\" :annotation some-face)) 250 | (company-elisp . (:icon \"yellow\" :selected (:background \"orange\" 251 | :foreground \"black\"))) 252 | (company-dabbrev . \"purple\"))") 253 | 254 | 255 | (defvar company-box-frame-parameters 256 | '((left . -1) 257 | (no-accept-focus . t) 258 | (no-focus-on-map . t) 259 | (min-width . 0) 260 | (width . 0) 261 | (min-height . 0) 262 | (height . 0) 263 | (internal-border-width . 1) 264 | (horizontal-scroll-bars . nil) 265 | (left-fringe . 0) 266 | (right-fringe . 0) 267 | (menu-bar-lines . 0) 268 | (tool-bar-lines . 0) 269 | (line-spacing . 0) 270 | ;; (unsplittable . nil) 271 | (undecorated . t) 272 | (top . -1) 273 | (visibility . nil) 274 | (mouse-wheel-frame . nil) 275 | (no-other-frame . t) 276 | (cursor-type . nil) 277 | (drag-internal-border . t) 278 | (left-fringe . 0) 279 | (right-fringe . 0) 280 | (tab-bar-lines . 0) 281 | (no-special-glyphs . t)) 282 | "Frame parameters used to create the frame.") 283 | 284 | (defvar company-box-debug-scrollbar nil) 285 | 286 | (defvar-local company-box--ov nil) 287 | (defvar-local company-box--ov-common nil) 288 | (defvar-local company-box--max 0) 289 | (defvar-local company-box--with-icons-p nil) 290 | (defvar-local company-box--x nil) 291 | (defvar-local company-box--top nil) 292 | (defvar-local company-box--space nil) 293 | (defvar-local company-box--height nil) 294 | (defvar-local company-box--scrollbar-window nil) 295 | (defvar-local company-box--parent-buffer nil) 296 | (defvar-local company-box--chunk-size 0) 297 | 298 | (defconst company-box--numbers 299 | (let ((vec (make-vector 20 nil))) 300 | (dotimes (index 20) 301 | (aset vec index 302 | (concat 303 | (string-trim (funcall company-quick-access-hint-function (mod index 10))) 304 | (and (> index 10) " ")))) 305 | vec)) 306 | 307 | (defvar company-box-selection-hook nil 308 | "Hook run when the selection changed.") 309 | 310 | 311 | (defalias 'company-box--icons-in-terminal 312 | (if (require 'icons-in-terminal nil t) 313 | 'icons-in-terminal 314 | (lambda (&rest _) " "))) 315 | 316 | (defun company-box--get-frame (&optional frame) 317 | "Return the company-box child frame on FRAME." 318 | (let ((frame (frame-local-getq company-box-frame frame))) 319 | (and (frame-live-p frame) frame))) 320 | 321 | (defsubst company-box--set-frame (frame) 322 | "Set the frame symbol ‘company-box-frame’ to FRAME." 323 | (frame-local-setq company-box-frame frame)) 324 | 325 | (defun company-box--get-id nil 326 | (or (frame-local-getq company-box-buffer-id) 327 | (frame-local-setq company-box-buffer-id (or (frame-parameter nil 'window-id) 328 | (frame-parameter nil 'name))))) 329 | 330 | (defun company-box--get-buffer (&optional suffix) 331 | "Construct the buffer name, it should be unique for each frame." 332 | (get-buffer-create 333 | (concat " *company-box-" (company-box--get-id) suffix "*"))) 334 | 335 | (defun company-box--with-icons-p nil 336 | (let ((spaces (+ (- (current-column) (string-width company-prefix)) 337 | (/ (or (car (nth 2 (posn-at-point (line-beginning-position)))) 0) 338 | (frame-char-width)) 339 | (car (window-edges nil t))))) 340 | (setq company-box--space spaces) 341 | (and company-box-enable-icon 342 | (> spaces 1)))) 343 | 344 | (defun company-box--make-scrollbar-parameter nil 345 | (cond ((eq company-box-scrollbar 'inherit) (frame-parameter nil 'vertical-scroll-bars)) 346 | ((eq company-box-scrollbar 'left) 'left) 347 | ((eq company-box-scrollbar 'right) 'right))) 348 | 349 | (defun company-box--make-frame (&optional buf) 350 | (let* ((after-make-frame-functions nil) 351 | (display-buffer-alist nil) 352 | (before-make-frame-hook nil) 353 | (buffer (or buf (company-box--get-buffer))) 354 | (params (append company-box-frame-parameters 355 | `((vertical-scroll-bars . ,(company-box--make-scrollbar-parameter)) 356 | (default-minibuffer-frame . ,(selected-frame)) 357 | (minibuffer . ,(minibuffer-window)) 358 | (inhibit-double-buffering . t) 359 | (background-color . ,(face-background 'company-tooltip nil t))))) 360 | (window (display-buffer-in-child-frame buffer `((child-frame-parameters . ,params)))) 361 | (frame (window-frame window))) 362 | (frame-local-setq company-box-buffer buffer frame) 363 | (set-frame-parameter frame 'desktop-dont-save t) 364 | (unless buf 365 | (frame-local-setq company-box-window window)) 366 | (set-window-dedicated-p window t) 367 | (redirect-frame-focus frame (frame-parent frame)) 368 | (set-frame-parameter frame 'name "") 369 | frame)) 370 | 371 | (defun company-box--get-ov nil 372 | (or company-box--ov 373 | (setq company-box--ov (make-overlay 1 1)))) 374 | 375 | (defun company-box--get-ov-common nil 376 | (or company-box--ov-common 377 | (setq company-box--ov-common (make-overlay 1 1)))) 378 | 379 | (defun company-box--extract-background (color) 380 | "COLOR can be a string, face or plist." 381 | `(:background 382 | ,(or (and (stringp color) color) 383 | (and (facep color) (face-background color nil t)) 384 | (let ((back (plist-get color :background))) 385 | (if (facep back) (face-background back nil t) back))))) 386 | 387 | (defun company-box--update-image (&optional color) 388 | "Change the image background color, because the overlay doesn't apply on it. 389 | The function either restore the original image or apply the COLOR. 390 | It doesn't nothing if a font icon is used." 391 | (-when-let* ((bol (line-beginning-position)) 392 | (point (text-property-any bol (min (+ bol 2) (point-max)) 'company-box-image t)) 393 | (image (get-text-property point 'display-origin)) 394 | (new-image (append image (and color (company-box--extract-background color))))) 395 | (put-text-property point (1+ point) 'display new-image))) 396 | 397 | (defvar-local company-box--numbers-pos nil) 398 | 399 | (defun company-box--remove-numbers (&optional side) 400 | (let ((side (or side (if (eq company-show-quick-access 'left) 'left-margin 'right-margin))) 401 | (max (point-max))) 402 | (--each company-box--numbers-pos 403 | (and (< it max) 404 | (get-text-property it 'company-box--number-pos) 405 | (put-text-property it (1+ it) 'display `((margin ,side) " ")))) 406 | (setq company-box--numbers-pos nil))) 407 | 408 | (defun company-box--update-numbers (start) 409 | (let ((side (if (eq company-show-quick-access 'left) 'left-margin 'right-margin)) 410 | (offset (if (eq company-show-quick-access 'left) 0 10)) 411 | (inhibit-redisplay t) 412 | (inhibit-modification-hooks t)) 413 | (company-box--remove-numbers side) 414 | (dotimes (index 10) 415 | (-some--> start 416 | (if (get-text-property it 'company-box--number-pos) 417 | it 418 | (next-single-property-change it 'company-box--number-pos)) 419 | (progn 420 | (push it company-box--numbers-pos) 421 | (setq start (1+ it))) 422 | (put-text-property (1- it) it 'display `((margin ,side) ,(aref company-box--numbers (+ index offset)))))))) 423 | 424 | (defun company-box--maybe-move-number (start) 425 | (when company-show-quick-access 426 | (company-box--update-numbers start))) 427 | 428 | (defvar-local company-box--last-scroll 0) 429 | (defvar-local company-box--last-start nil) 430 | 431 | (defun company-box--handle-scroll (_win new-start) 432 | (setq company-box--last-start new-start) 433 | (when company-box--x 434 | (when (>= (abs (- company-box--last-scroll (or company-selection 0))) 435 | company-box--chunk-size) 436 | (company-box--ensure-full-window-is-rendered new-start)) 437 | (setq company-box--last-scroll (or company-selection 0)) 438 | (company-box--maybe-move-number new-start) 439 | (company-box--set-width new-start))) 440 | 441 | (defun company-box--move-overlay-no-selection nil 442 | (goto-char 1) 443 | (move-overlay (company-box--get-ov) 1 1) 444 | (move-overlay (company-box--get-ov-common) 1 1)) 445 | 446 | (defun company-box--end-of-common (start eol) 447 | (while (let ((face (get-text-property start 'face))) 448 | (and (or (eq face 'company-tooltip-common) 449 | (and (listp face) 450 | (memq 'company-tooltip-common face))) 451 | (not (eq start eol)))) 452 | (setq start (next-single-property-change start 'face nil eol))) 453 | start) 454 | 455 | (defun company-box--move-overlays (selection &optional new-point) 456 | (if (null selection) 457 | (company-box--move-overlay-no-selection) 458 | (company-box--update-image) 459 | (goto-char (if new-point new-point (company-box--point-at-line selection))) 460 | (let* ((bol (line-beginning-position)) 461 | (eol (line-beginning-position 2)) 462 | (inhibit-modification-hooks t) 463 | (start-common (next-single-property-change bol 'company-box--candidate-string nil eol)) 464 | (end-common (company-box--end-of-common start-common eol))) 465 | (move-overlay (company-box--get-ov) bol eol) 466 | (move-overlay (company-box--get-ov-common) start-common end-common)) 467 | (let ((color (or (get-text-property (point) 'company-box--color) 468 | 'company-tooltip-selection)) 469 | (inhibit-modification-hooks t)) 470 | (overlay-put (company-box--get-ov) 'face color) 471 | (overlay-put (company-box--get-ov-common) 'face 'company-tooltip-common-selection) 472 | (company-box--update-image color)))) 473 | 474 | 475 | (defun company-box--get-candidates-between (start end) 476 | (let ((index 0) 477 | (vector (make-vector (max (- end start) 1) nil))) 478 | (while (< start end) 479 | (-when-let* ((candidate (get-text-property start 'company-box-candidate))) 480 | (aset vector index candidate) 481 | (setq index (1+ index))) 482 | (setq start (1+ start))) 483 | ;; Return nil when the vector is empty 484 | (and (aref vector 0) vector))) 485 | 486 | (defvar-local company-box--first-render nil) 487 | 488 | (defun company-box--get-start (point height) 489 | (previous-single-property-change 490 | (1+ point) 'company-box--rendered nil (max 1 (- point height)))) 491 | 492 | (defun company-box--get-end (point height) 493 | (next-single-property-change 494 | point 'company-box--rendered nil (min (point-max) (+ point height)))) 495 | 496 | (defun company-box--render-lines (point &optional no-remove-numbers) 497 | (when-let* ((height (1+ company-box--chunk-size)) 498 | (start (company-box--get-start point height)) 499 | (end (company-box--get-end point height)) 500 | (candidates (company-box--get-candidates-between start end)) 501 | (inhibit-modification-hooks t) 502 | (inhibit-redisplay t)) 503 | (unless no-remove-numbers 504 | (company-box--remove-numbers)) 505 | (save-excursion 506 | (delete-region start end) 507 | (goto-char start) 508 | (insert 509 | (with-current-buffer company-box--parent-buffer 510 | (--> candidates 511 | (mapcar (-compose 'company-box--make-line 'company-box--make-candidate) it) 512 | (mapconcat 'identity it "\n"))) 513 | "\n") 514 | (put-text-property start (point) 'company-box--rendered t)))) 515 | 516 | (defun company-box--render-buffer (string on-update) 517 | (let ((buffer (current-buffer)) 518 | (inhibit-modification-hooks t) 519 | (candidates-length company-candidates-length) 520 | (show-numbers company-show-quick-access) 521 | (with-icons-p company-box--with-icons-p) 522 | (window-configuration-change-hook nil) 523 | (buffer-list-update-hook nil)) 524 | (with-current-buffer (company-box--get-buffer) 525 | (erase-buffer) 526 | (insert string) 527 | (put-text-property (point-min) (point-max) 'company-box--rendered nil) 528 | (setq company-box--first-render t 529 | company-candidates-length candidates-length 530 | company-show-quick-access show-numbers 531 | company-box--with-icons-p with-icons-p) 532 | (unless on-update 533 | (setq mode-line-format nil 534 | header-line-format nil 535 | display-line-numbers nil 536 | truncate-lines t 537 | show-trailing-whitespace nil 538 | company-box--parent-buffer buffer 539 | company-box--first-render t 540 | cursor-in-non-selected-windows nil) 541 | (setq-local scroll-step 1) 542 | (setq-local scroll-conservatively 100000) 543 | (setq-local scroll-margin 0) 544 | (setq-local bidi-display-reordering nil) 545 | (setq-local redisplay--inhibit-bidi t) 546 | ;; (setq-local next-screen-context-lines 0) 547 | (setq-local scroll-preserve-screen-position t) 548 | (setq-local fontification-functions nil) 549 | (setq-local window-scroll-functions '(company-box--handle-scroll)) 550 | ;; (setq-local pre-redisplay-function '(company-box--handle-state-changed)) 551 | ;; (setq-local pre-redisplay-functions '(company-box--handle-state-changed)) 552 | ;;(setq-local window-state-change-functions '(company-box--handle-state-changed)) 553 | ;;(setq-local window-state-change-hook '(company-box--handle-state-changed)) 554 | ;; (setq-local company-box--chunk-size (or 10 (frame-height) 50)) 555 | ;; (jit-lock-mode 1) 556 | (add-hook 'window-configuration-change-hook 'company-box--prevent-changes t t) 557 | )))) 558 | 559 | (defvar-local company-box--bottom nil) 560 | 561 | (defun company-box--point-bottom nil 562 | (or company-box--bottom 563 | (setq company-box--bottom 564 | (let* ((win (let ((tmp nil)) 565 | (while (window-in-direction 'below tmp) 566 | (setq tmp (window-in-direction 'below tmp))) 567 | tmp))) 568 | (+ (or (nth 2 (window-line-height 'mode-line win)) 569 | (- (frame-pixel-height) (* (frame-char-height) 3))) 570 | (or (and win (nth 1 (window-edges win t nil t))) 571 | 0)))))) 572 | 573 | (defvar-local company-box--prefix-pos nil) 574 | (defvar-local company-box--edges nil) 575 | 576 | (defun company-box--prefix-pos nil 577 | (if (eq company-box-frame-behavior 'point) 578 | (nth 2 (posn-at-point (point))) 579 | (or company-box--prefix-pos 580 | (setq company-box--prefix-pos 581 | (nth 2 (posn-at-point (- (point) (length company-prefix)))))))) 582 | 583 | (defun company-box--edges nil 584 | (or company-box--edges 585 | (setq company-box--edges (window-edges nil t nil t)))) 586 | 587 | (defun company-box--compute-frame-position (frame) 588 | (-let* ((window-configuration-change-hook nil) 589 | ((left top _right _bottom) (company-box--edges)) 590 | (window-tab-line-height (if (fboundp 'window-tab-line-height) 591 | (window-tab-line-height) 592 | 0)) 593 | (top (+ top window-tab-line-height company-box-frame-top-margin)) 594 | (char-height (frame-char-height frame)) 595 | (char-width (frame-char-width frame)) 596 | (height (* (min company-candidates-length company-tooltip-limit) char-height)) 597 | (space-numbers (if (eq company-show-quick-access 'left) char-width 0)) 598 | (frame-resize-pixelwise t) 599 | (mode-line-y (company-box--point-bottom)) 600 | ((p-x . p-y) (company-box--prefix-pos)) 601 | (p-y-abs (+ top p-y)) 602 | (y (or (and (> p-y-abs (/ mode-line-y 2)) 603 | (<= (- mode-line-y p-y) (+ char-height height)) 604 | (> (- p-y-abs height) 0) 605 | (- p-y height)) 606 | (+ p-y char-height))) 607 | (height (or (and (> y p-y) 608 | (> height (- mode-line-y y)) 609 | (- mode-line-y y)) 610 | height)) 611 | (height (- height (mod height char-height))) 612 | (scrollbar-width (if (eq company-box-scrollbar 'left) (frame-scroll-bar-width frame) 0)) 613 | (x (if (eq company-box-frame-behavior 'point) 614 | p-x 615 | (if company-box--with-icons-p 616 | (- p-x (* char-width (+ company-box-icon-right-margin (if (= company-box--space 2) 2 3))) space-numbers scrollbar-width) 617 | (- p-x (if (= company-box--space 0) 0 char-width) space-numbers scrollbar-width))))) 618 | (setq company-box--x (max (+ x left) 0) 619 | company-box--top (+ y top) 620 | company-box--height height 621 | company-box--chunk-size (/ height char-height)) 622 | (with-current-buffer (company-box--get-buffer) 623 | (setq company-box--x (max (+ x left) 0) 624 | company-box--top (+ y top) 625 | company-box--height height 626 | company-box--chunk-size (/ height char-height))))) 627 | 628 | (defun company-box--update-frame-position (frame) 629 | (-let (((new-x . width) (company-box--set-width nil t)) 630 | (window-configuration-change-hook nil) 631 | (buffer-list-update-hook nil) 632 | (inhibit-redisplay t)) 633 | (frame-local-setq company-box-window-origin (selected-window) frame) 634 | (frame-local-setq company-box-buffer-origin (current-buffer) frame) 635 | (modify-frame-parameters 636 | frame 637 | `((width . (text-pixels . ,width)) 638 | (height . (text-pixels . ,company-box--height)) 639 | (user-size . t) 640 | (left . (+ ,(round (or new-x company-box--x)))) 641 | (top . (+ ,company-box--top)) 642 | (user-position . t) 643 | (right-fringe . 0) 644 | (left-fringe . 0))))) 645 | 646 | (defun company-box--display (string on-update) 647 | "Display the completions." 648 | (company-box--render-buffer string on-update) 649 | (unless (company-box--get-frame) 650 | (company-box--set-frame (company-box--make-frame))) 651 | (company-box--compute-frame-position (company-box--get-frame)) 652 | (company-box--move-selection t) 653 | (company-box--update-frame-position (company-box--get-frame)) 654 | (unless (frame-visible-p (company-box--get-frame)) 655 | (make-frame-visible (company-box--get-frame))) 656 | (company-box--update-scrollbar (company-box--get-frame) t) 657 | (with-current-buffer (company-box--get-buffer) 658 | (company-box--maybe-move-number (or company-box--last-start 1)))) 659 | 660 | (defun company-box--get-kind (candidate) 661 | (let ((list company-box-icons-functions) 662 | kind) 663 | (while (and (null kind) list) 664 | (setq kind (funcall (car list) candidate)) 665 | (pop list)) 666 | (or kind 'Unknown))) 667 | 668 | (defun company-box--get-icon (icon) 669 | (cond ((listp icon) 670 | (cond ((eq 'image (car icon)) 671 | (unless (plist-get icon :height) 672 | (setq icon (append icon `(:height ,(round (* (frame-char-height) 0.90)))))) 673 | (propertize " " 'display icon 'company-box-image t 674 | 'display-origin icon)) 675 | ((and company-box-color-icon icon) 676 | (apply 'company-box--icons-in-terminal icon)) 677 | (t (company-box--icons-in-terminal (or (car icon) 'fa_question_circle))))) 678 | ((symbolp icon) 679 | (company-box--icons-in-terminal (or icon 'fa_question_circle))) 680 | (t icon))) 681 | 682 | (defun company-box--add-icon (candidate) 683 | (-let* ((icon (alist-get (company-box--get-kind candidate) 684 | (symbol-value company-box-icons-alist))) 685 | (is-image (and (listp icon) (eq 'image (car icon)))) 686 | (icon-string (company-box--get-icon icon)) 687 | (display-props (unless is-image (get-text-property 0 'display icon-string)))) 688 | (concat 689 | (cond (is-image icon-string) 690 | (display-props 691 | ;; The string already has a display prop, add height to it 692 | (--> (if (listp (car display-props)) 693 | (append display-props '((height 0.95))) 694 | (append `(,display-props) '((height 0.95)))) 695 | (put-text-property 0 (length icon-string) 'display it icon-string)) 696 | icon-string) 697 | (t 698 | ;; Make sure the string is not bigger than other text. 699 | ;; It causes invalid computation of the frame size, .. 700 | (put-text-property 0 (length icon-string) 'display '((height 0.95)) icon-string) 701 | icon-string)) 702 | (propertize " " 'display `(space :align-to (+ company-box-icon-right-margin 703 | left-fringe 704 | ,(if (> company-box--space 2) 3 2))))))) 705 | 706 | (defun company-box--get-color (backend) 707 | (alist-get backend company-box-backends-colors)) 708 | 709 | (defun company-box--resolve-color (color key) 710 | (or (and (stringp color) color) 711 | (and (listp color) (or (plist-get color key) (plist-get color :all))))) 712 | 713 | (defun company-box--resolve-colors (color) 714 | (when color 715 | (list 716 | (company-box--resolve-color color :candidate) 717 | (company-box--resolve-color color :annotation) 718 | (company-box--resolve-color color :icon) 719 | (let ((color (company-box--resolve-color color :selected))) 720 | (unless (stringp color) 721 | color))))) 722 | 723 | (defun company-box--apply-color (string color) 724 | (when color 725 | (add-face-text-property 0 (length string) 726 | (if (stringp color) (list :foreground color) color) 727 | nil string)) 728 | string) 729 | 730 | (defun company-box--candidate-string (candidate length-candidate) 731 | (let* ((company-tooltip-align-annotations nil) 732 | (company-tooltip-margin 0) 733 | (company-candidates nil) 734 | (string (-> (company--clean-string candidate) 735 | (company-fill-propertize nil length-candidate nil nil nil)))) 736 | (add-text-properties 0 (length string) '(company-box--candidate-string t) string) 737 | string)) 738 | 739 | (defun company-box--make-number-prop nil 740 | (let ((side (if (eq company-show-quick-access 'left) 'left-margin 'right-margin))) 741 | (propertize " " 'company-box--number-pos t 'display `((margin ,side) " ")))) 742 | 743 | (defun company-box--make-line (candidate) 744 | (-let* (((candidate annotation len-c len-a backend) candidate) 745 | (color (company-box--get-color backend)) 746 | ((c-color a-color i-color s-color) (company-box--resolve-colors color)) 747 | (icon-string (and company-box--with-icons-p (company-box--add-icon candidate))) 748 | (candidate-string (company-box--candidate-string candidate len-c)) 749 | (align-string (when annotation 750 | (concat " " (and company-tooltip-align-annotations 751 | (propertize " " 'display `(space :align-to (- right-margin ,len-a 1))))))) 752 | (space company-box--space) 753 | (icon-p company-box-enable-icon) 754 | (annotation-string (and annotation (propertize annotation 'face 'company-tooltip-annotation))) 755 | (line (concat (unless (or (and (= space 2) icon-p) (= space 0)) 756 | (propertize " " 'display `(space :width ,(if (or (= space 1) (not icon-p)) 1 0.75)))) 757 | (company-box--apply-color icon-string i-color) 758 | (when company-show-quick-access 759 | (company-box--make-number-prop)) 760 | (company-box--apply-color candidate-string c-color) 761 | align-string 762 | (company-box--apply-color annotation-string a-color) 763 | ;; Trick to make sure the selection face goes until the end, even without :extend 764 | (propertize " " 'display `(space :align-to right-fringe)))) 765 | (len (length line))) 766 | (add-text-properties 0 len (list 'company-box--len (+ len-c len-a) 767 | 'company-box--color s-color 768 | 'mouse-face 'company-tooltip-mouse) 769 | line) 770 | line)) 771 | 772 | (defun company-box--backend (candidate) 773 | (or (get-text-property 0 'company-backend candidate) 774 | (and (symbolp company-backend) company-backend) 775 | (--first (and it (not (keywordp it))) company-backend))) 776 | 777 | (defun company-box--make-candidate (candidate) 778 | (let* ((annotation (-some->> (company-call-backend 'annotation candidate) 779 | (replace-regexp-in-string "[ \t\n\r]+" " ") 780 | (string-trim))) 781 | (len-candidate (string-width candidate)) 782 | (len-annotation (if annotation (string-width annotation) 0)) 783 | (len-total (+ len-candidate len-annotation)) 784 | (backend (company-box--backend candidate))) 785 | (when (> len-total company-box--max) 786 | (setq company-box--max len-total)) 787 | (list candidate 788 | annotation 789 | len-candidate 790 | len-annotation 791 | backend))) 792 | 793 | (defvar-local company-box--parent-start nil) 794 | 795 | (defun company-box-show (&optional on-update) 796 | (unless on-update 797 | (setq company-box--parent-start (window-start)) 798 | (add-hook 'window-scroll-functions 'company-box--handle-scroll-parent nil t)) 799 | (company-box--save) 800 | (setq company-box--max 0 801 | company-box--with-icons-p (company-box--with-icons-p)) 802 | (let ((string (make-string company-candidates-length 10))) 803 | (--each-indexed company-candidates 804 | (put-text-property it-index (1+ it-index) 'company-box-candidate it string)) 805 | (company-box--display string on-update))) 806 | 807 | (defvar company-box-hide-hook nil) 808 | 809 | (defun company-box-hide nil 810 | (setq company-box--bottom nil 811 | company-box--x nil 812 | company-box--prefix-pos nil 813 | company-box--last-start nil 814 | company-box--edges nil) 815 | (-some-> (company-box--get-frame) 816 | (make-frame-invisible)) 817 | (with-current-buffer (company-box--get-buffer) 818 | (setq company-box--last-start nil)) 819 | (remove-hook 'window-scroll-functions 'company-box--handle-scroll-parent t) 820 | (run-hook-with-args 'company-box-hide-hook (or (frame-parent) (selected-frame)))) 821 | 822 | (defun company-box--calc-len (buffer start end char-width) 823 | (let ((max 0)) 824 | (with-current-buffer buffer 825 | (save-excursion 826 | (goto-char start) 827 | (while (< (point) end) 828 | (let ((len (or (get-text-property (point) 'company-box--len) 0))) 829 | (when (> len max) 830 | (setq max len))) 831 | (forward-line)))) 832 | (* (+ max (if company-box--with-icons-p 6 2) (if company-show-quick-access 2 0)) 833 | char-width))) 834 | 835 | (defun company-box--get-start-end-for-width (win win-start) 836 | (let ((height company-box--chunk-size) 837 | (selection (or company-selection 0)) 838 | (box-buffer (window-buffer win))) 839 | (if win-start 840 | (cons win-start (with-current-buffer box-buffer 841 | (company-box--point-at-line height win-start))) 842 | ;; When window-start is not known, we take the points (selection - height) 843 | ;; and (selection + height) 844 | (with-current-buffer box-buffer 845 | (let ((start (company-box--point-at-line (- selection height)))) 846 | (cons start (company-box--point-at-line height start))))))) 847 | 848 | (defun company-box--set-width (&optional win-start value-only) 849 | (-let* ((inhibit-redisplay t) 850 | (frame (company-box--get-frame (frame-parent))) 851 | (window (frame-local-getq company-box-window (frame-parent))) 852 | (char-width (frame-char-width frame)) 853 | (current-width (frame-inner-width frame)) 854 | ((start . end) (company-box--get-start-end-for-width window win-start)) 855 | (width (+ (company-box--calc-len (window-buffer window) start end char-width) 856 | (if (and (eq company-box-scrollbar t) (company-box--scrollbar-p frame)) (* 2 char-width) 0) 857 | char-width)) 858 | (width (max (min width 859 | (* company-tooltip-maximum-width char-width)) 860 | (* company-tooltip-minimum-width char-width) 861 | (if (and company-tooltip-width-grow-only 862 | ;; Will only be true when updating 863 | (frame-visible-p frame)) 864 | current-width 865 | 0))) 866 | (diff (abs (- (frame-pixel-width frame) width))) 867 | (frame-width (frame-pixel-width (frame-parent))) 868 | (new-x (and (> (+ width company-box--x) frame-width) 869 | (max 0 (- frame-width width char-width))))) 870 | (when company-box-debug-scrollbar 871 | (message "[RESIZE] NEW-WIDTH=%s NEW-PIXEL=%s OLD=%s OLD-PIXEL=%s" 872 | (/ width char-width) width (frame-parameter frame 'width) (frame-pixel-width frame))) 873 | (or (and value-only (cons new-x width)) 874 | (and (> diff 2) 875 | (modify-frame-parameters 876 | frame 877 | `((width . (text-pixels . ,width)) 878 | (left . (+ ,(round (or new-x company-box--x)))))))))) 879 | 880 | (defun company-box--percent (a b) 881 | (/ (float a) (float b))) 882 | 883 | (defun company-box--scrollbar-p (frame) 884 | (/= 1 (company-box--percent 885 | company-box--height 886 | (* company-candidates-length 887 | (frame-char-height frame))))) 888 | 889 | (defun company-box--scrollbar-prevent-changes (&rest _) 890 | (when company-box-debug-scrollbar 891 | (message "[CHANGES] CURRENT-BUFFER=%s MIN-WIDTH=%s SAFE-MIN-WIDTH=%s MIN-SIZE=%s MIN-SIZE-IGNORE=%s" 892 | (current-buffer) window-min-width window-safe-min-width 893 | (window-min-size nil t) (window-min-size nil t t))) 894 | (let ((window-min-width 2) 895 | (window-safe-min-width 2) 896 | (ignore-window-parameters t) 897 | (current-size (window-size nil t))) 898 | (when company-box-debug-scrollbar 899 | (message "[CHANGES] MIN CURRENT-SIZE=%s WIN-MIN-SIZE=%s WIN-PARAMS=%s FRAME-PARAMS=%s HOOKS=%s" 900 | current-size (window-min-size nil t) (window-parameters) (frame-parameters (company-box--get-frame)) 901 | window-configuration-change-hook)) 902 | (unless (= current-size 2) 903 | (minimize-window)))) 904 | 905 | (defun company-box--update-scrollbar-buffer (height-blank height-scrollbar percent buffer) 906 | (with-current-buffer buffer 907 | (erase-buffer) 908 | (setq header-line-format nil 909 | mode-line-format nil 910 | show-trailing-whitespace nil 911 | cursor-in-non-selected-windows nil) 912 | (setq-local window-min-width 2) 913 | (setq-local window-safe-min-width 2) 914 | (unless (zerop height-blank) 915 | (insert (propertize " " 'display `(space :align-to right-fringe :height ,height-blank)) 916 | (propertize "\n" 'face (list :height 1)))) 917 | (setq height-scrollbar (if (= percent 1) 918 | ;; Due to float/int casting in the emacs code, there might 1 or 2 919 | ;; remainings pixels 920 | (+ height-scrollbar 10) 921 | height-scrollbar)) 922 | (insert (propertize " " 'face (list :background (face-background 'company-box-scrollbar nil t)) 923 | 'display `(space :align-to right-fringe :height ,height-scrollbar))) 924 | (add-hook 'window-configuration-change-hook 'company-box--scrollbar-prevent-changes t t) 925 | (current-buffer))) 926 | 927 | (defun company-box--update-scrollbar (frame &optional first) 928 | (when (eq company-box-scrollbar t) 929 | (let* ((selection (or company-selection 0)) 930 | (buffer (company-box--get-buffer "-scrollbar")) 931 | (h-frame company-box--height) 932 | (n-elements company-candidates-length) 933 | (percent (company-box--percent selection (1- n-elements))) 934 | (percent-display (company-box--percent h-frame (* n-elements (frame-char-height frame)))) 935 | (scrollbar-pixels (* h-frame percent-display)) 936 | (height-scrollbar (/ scrollbar-pixels (frame-char-height frame))) 937 | (blank-pixels (* (- h-frame scrollbar-pixels) percent)) 938 | (height-blank (/ blank-pixels (frame-char-height frame))) 939 | (inhibit-redisplay t) 940 | (inhibit-eval-during-redisplay t) 941 | (window-configuration-change-hook nil) 942 | (window-scroll-functions nil)) 943 | (when company-box-debug-scrollbar 944 | (message "[SCROLL] SELECTION=%s BUFFER=%s H-FRAME=%s N-ELEMENTS=%s PERCENT=%s PERCENT-DISPLAY=%s SCROLLBAR-PIXEL=%s HEIGHT=SCROLLBAR=%s BLANK-PIXELS=%s HEIGHT-BLANK=%s FRAME-CHAR-HEIGHT=%s FRAME-CHAR-HEIGHT-NO-FRAME=%s FRAME=%s MUL=%s" 945 | selection buffer h-frame n-elements percent percent-display scrollbar-pixels height-scrollbar blank-pixels height-blank (frame-char-height frame) (frame-char-height) frame (* n-elements (frame-char-height frame)))) 946 | (cond 947 | ((and first (= percent-display 1) (window-live-p company-box--scrollbar-window)) 948 | (delete-window company-box--scrollbar-window)) 949 | ((window-live-p company-box--scrollbar-window) 950 | (company-box--update-scrollbar-buffer height-blank height-scrollbar percent buffer)) 951 | ((/= percent-display 1) 952 | (setq 953 | company-box--scrollbar-window 954 | (with-selected-frame (company-box--get-frame) 955 | (let* ((window-min-width 2) 956 | (window-safe-min-width 2) 957 | (window-configuration-change-hook nil) 958 | (display-buffer-alist nil) 959 | (window-scroll-functions nil)) 960 | (display-buffer-in-side-window 961 | (company-box--update-scrollbar-buffer height-blank height-scrollbar percent buffer) 962 | '((side . right) (window-width . 2)))))) 963 | (frame-local-setq company-box-scrollbar (window-buffer company-box--scrollbar-window) frame)))))) 964 | 965 | ;; ;; (message "selection: %s len: %s PERCENT: %s PERCENTS-DISPLAY: %s SIZE-FRAME: %s HEIGHT-S: %s HEIGHT-B: %s h-frame: %s sum: %s" 966 | ;; ;; selection n-elements percent percent-display height height-scrollbar height-blank height (+ height-scrollbar height-blank)) 967 | ;; ;; (message "HEIGHT-S-1: %s HEIGHT-B-1: %s sum: %s" scrollbar-pixels blank-pixels (+ height-scrollbar-1 height-blank-1)) 968 | 969 | (defun company-box--point-at-line (&optional line start) 970 | (save-excursion 971 | (goto-char (or start 1)) 972 | (forward-line (or line company-selection 0)) 973 | (point))) 974 | 975 | (defun company-box--move-selection (&optional first-render) 976 | (let ((selection company-selection) 977 | (candidates-length company-candidates-length) 978 | (inhibit-redisplay t) 979 | (inhibit-modification-hooks t) 980 | (buffer-list-update-hook nil) 981 | (window-configuration-change-hook nil)) 982 | (with-selected-window (get-buffer-window (company-box--get-buffer) t) 983 | (setq company-selection selection) 984 | (let ((new-point (company-box--point-at-line selection)) 985 | (buffer-list-update-hook nil) 986 | (window-configuration-change-hook nil)) 987 | (cond ((and (> new-point 1) (null (get-text-property (1- new-point) 'company-box--rendered))) 988 | ;; When going backward, render lines not yet visible 989 | ;; This avoid to render the lines when it's already visible 990 | ;; causing window-start to jump 991 | (company-box--render-lines (1- new-point)) 992 | (company-box--move-overlays selection)) 993 | ((get-text-property new-point 'company-box--rendered) 994 | ;; Line is already rendered, just move overlays 995 | (company-box--move-overlays selection new-point)) 996 | (t 997 | ;; Line is not rendered at point 998 | (company-box--render-lines new-point) 999 | (company-box--move-overlays selection)))) 1000 | (when (equal selection (1- candidates-length)) 1001 | ;; Ensure window doesn't go past last candidate 1002 | (--> (- company-box--chunk-size) 1003 | (company-box--point-at-line it (point-max)) 1004 | (set-window-start nil it)))) 1005 | (unless first-render 1006 | (company-box--update-scrollbar (company-box--get-frame) first-render)) 1007 | (run-with-timer 0 nil (lambda nil (run-hook-with-args 'company-box-selection-hook selection 1008 | (or (frame-parent) (selected-frame))))))) 1009 | 1010 | (defun company-box--prevent-changes (&rest _) 1011 | (set-window-margins 1012 | nil 1013 | (if (eq company-show-quick-access 'left) 1 0) 1014 | (if (eq company-show-quick-access 't) 2 0))) 1015 | 1016 | (defun company-box--handle-window-changes (&optional on-idle) 1017 | (-when-let* ((frame (company-box--get-frame))) 1018 | (and (frame-live-p frame) 1019 | (frame-visible-p frame) 1020 | (or (not (eq (selected-window) (frame-local-getq company-box-window-origin frame))) 1021 | (not (eq (window-buffer) (frame-local-getq company-box-buffer-origin frame)))) 1022 | (if on-idle (company-box-hide) 1023 | ;; Handle when this function (in `buffer-list-update-hook') has been 1024 | ;; triggered by a function that select only temporary another window/buffer. 1025 | ;; So we are sure to not be in a false positive case. 1026 | ;; See the docstring of `select-window' 1027 | (run-with-idle-timer 0 nil (lambda nil (company-box--handle-window-changes t))))))) 1028 | 1029 | (defun company-box--hide-single-candidate nil 1030 | (or (eq company-box-show-single-candidate 'never) 1031 | (and (eq company-box-show-single-candidate 'when-no-other-frontend) 1032 | (cdr company-frontends)))) 1033 | 1034 | (defvar-local company-box--state nil) 1035 | 1036 | (defun company-box--save nil 1037 | (setq company-box--state 1038 | (list company-prefix 1039 | company-common 1040 | company-search-string 1041 | company-candidates-length 1042 | ;; company-candidates 1043 | ))) 1044 | 1045 | (defun company-box--update nil 1046 | (-let* (((prefix common search length) company-box--state) 1047 | (frame (company-box--get-frame)) 1048 | (window-configuration-change-hook nil) 1049 | (frame-visible (and (frame-live-p frame) (frame-visible-p frame)))) 1050 | (if (and frame-visible 1051 | (equal search company-search-string) 1052 | (equal length company-candidates-length) 1053 | (string= company-prefix prefix) 1054 | (string= company-common common)) 1055 | (company-box--move-selection) 1056 | (company-box-show frame-visible)))) 1057 | 1058 | (defun company-box--handle-scroll-parent (win new-start) 1059 | (when (and (eq (frame-local-getq company-box-window-origin (company-box--get-frame)) win) 1060 | (not (equal company-box--parent-start new-start))) 1061 | (company-box--on-start-change) 1062 | (setq company-box--parent-start new-start))) 1063 | 1064 | (defvar company-mouse-event) 1065 | (defun company-box--select-mouse () 1066 | "Select the candidate from `company-mouse-event'." 1067 | (let ((posn (event-end company-mouse-event))) 1068 | (when (eq (company-box--get-buffer) (window-buffer (posn-window posn))) 1069 | (setq company-selection 1070 | (with-current-buffer (company-box--get-buffer) 1071 | (1- (line-number-at-pos (posn-point posn))))) 1072 | (company-box--move-selection) 1073 | ;; success 1074 | t))) 1075 | 1076 | (defun company-box-frontend (command) 1077 | "`company-mode' frontend using child-frame. 1078 | COMMAND: See `company-frontends'." 1079 | ;; (message "\nCOMMMAND: %s last=%s this=%s" command last-command this-command) 1080 | ;; (message "prefix: %s" company-prefix) 1081 | ;; (message "candidates: %s" company-candidates) 1082 | ;; (message "common: %s" company-common) 1083 | ;; (message "selection: %s" company-selection) 1084 | ;; (message "point: %s" company-point) 1085 | ;; (message "search-string: %s" company-search-string) 1086 | ;;(message "last-command: %s" last-command) 1087 | (cond 1088 | ((eq command 'hide) 1089 | (company-box-hide)) 1090 | ((and (equal company-candidates-length 1) 1091 | (company-box--hide-single-candidate)) 1092 | (company-box-hide)) 1093 | ((eq command 'show) 1094 | (company-box-show)) 1095 | ((eq command 'update) 1096 | (company-box--update)) 1097 | ((eq command 'select-mouse) 1098 | (company-box--select-mouse)) 1099 | ;; ((eq command 'post-command) 1100 | ;; (company-box--post-command)) 1101 | )) 1102 | 1103 | (defun company-box--ensure-full-window-is-rendered (&optional start) 1104 | (let ((window-configuration-change-hook nil) 1105 | (buffer-list-update-hook nil)) 1106 | (with-selected-window (get-buffer-window (company-box--get-buffer) t) 1107 | (let* ((start (or start (window-start))) 1108 | (line-end company-box--chunk-size) 1109 | (end (company-box--point-at-line line-end start)) 1110 | (nlines (- end start))) 1111 | (dotimes (index nlines) 1112 | (unless (get-text-property (- end (1+ index)) 'company-box--rendered) 1113 | (company-box--render-lines (- end (1+ index)) t))))))) 1114 | 1115 | (defun company-box--on-start-change nil 1116 | (setq company-box--prefix-pos nil 1117 | company-box--edges nil) 1118 | (let ((frame (company-box--get-frame)) 1119 | (inhibit-redisplay t) 1120 | (inhibit-modification-hooks t) 1121 | (window-scroll-functions nil)) 1122 | (when (and (frame-live-p frame) (frame-visible-p frame)) 1123 | (company-box--compute-frame-position frame) 1124 | (company-box--ensure-full-window-is-rendered) 1125 | (company-box--update-frame-position frame)))) 1126 | 1127 | (defun company-box--delete-frame () 1128 | "Delete the child frame if it exists." 1129 | (-when-let (frame (company-box--get-frame)) 1130 | (and (frame-live-p frame) 1131 | (delete-frame frame)) 1132 | (company-box--set-frame nil))) 1133 | 1134 | (defun company-box--kill-delay (buffer) 1135 | (run-with-idle-timer 1136 | 0 nil (lambda nil 1137 | (when (buffer-live-p buffer) 1138 | (kill-buffer buffer))))) 1139 | 1140 | (defun company-box--kill-buffer (frame) 1141 | (company-box--kill-delay (frame-local-getq company-box-buffer frame)) 1142 | (company-box--kill-delay (frame-local-getq company-box-scrollbar frame))) 1143 | 1144 | (defun company-box--is-box-buffer (&optional buffer) 1145 | (or (and buffer (eq buffer (frame-local-getq company-box--dimmer-parent (frame-parent)))) 1146 | (string-prefix-p " *company-box" (buffer-name (or buffer (window-buffer)))))) 1147 | 1148 | (defun company-box--dimmer-show (&rest _) 1149 | (frame-local-setq company-box--dimmer-parent (window-buffer))) 1150 | 1151 | (defun company-box--dimmer-hide (&rest _) 1152 | (frame-local-setq company-box--dimmer-parent nil)) 1153 | 1154 | (defun company-box--handle-theme-change (&rest _) 1155 | ;; Deleting frames will force to rebuild them from scratch 1156 | ;; and use the correct new colors 1157 | (company-box-doc--delete-frame) 1158 | (company-box--delete-frame)) 1159 | 1160 | (defun company-box--tweak-external-packages nil 1161 | (with-eval-after-load 'dimmer 1162 | (when (boundp 'dimmer-prevent-dimming-predicates) 1163 | (add-to-list 1164 | 'dimmer-prevent-dimming-predicates 1165 | 'company-box--is-box-buffer)) 1166 | (when (boundp 'dimmer-buffer-exclusion-predicates) 1167 | (add-to-list 1168 | 'dimmer-buffer-exclusion-predicates 1169 | 'company-box--is-box-buffer)) 1170 | (advice-add 'load-theme :before 'company-box--handle-theme-change) 1171 | (advice-add 'company-box-show :before 'company-box--dimmer-show) 1172 | (advice-add 'company-box-hide :before 'company-box--dimmer-hide)) 1173 | (with-eval-after-load 'golden-ratio 1174 | (when (boundp 'golden-ratio-exclude-buffer-regexp) 1175 | (add-to-list 'golden-ratio-exclude-buffer-regexp " *company-box")))) 1176 | 1177 | (defun company-box--set-mode (&optional frame) 1178 | (cond 1179 | ((and (bound-and-true-p company-box-mode) (not (display-graphic-p frame))) 1180 | (company-box-mode -1)) 1181 | ((bound-and-true-p company-box-mode) 1182 | (company-box--tweak-external-packages) 1183 | (remove-hook 'after-make-frame-functions 'company-box--set-mode t) 1184 | (add-hook 'delete-frame-functions 'company-box--kill-buffer) 1185 | (add-hook 'buffer-list-update-hook 'company-box--handle-window-changes t) 1186 | (make-local-variable 'company-frontends) 1187 | (setq company-frontends (->> (delq 'company-pseudo-tooltip-frontend company-frontends) 1188 | (delq 'company-pseudo-tooltip-unless-just-one-frontend))) 1189 | (add-to-list 'company-frontends 'company-box-frontend) 1190 | (unless (assq 'company-box-frame frameset-filter-alist) 1191 | (push '(company-box-doc-frame . :never) frameset-filter-alist) 1192 | (push '(company-box-frame . :never) frameset-filter-alist))) 1193 | ((memq 'company-box-frontend company-frontends) 1194 | (setq company-frontends (delq 'company-box-frontend company-frontends)) 1195 | (add-to-list 'company-frontends 'company-pseudo-tooltip-unless-just-one-frontend)))) 1196 | 1197 | (add-hook 'company-box-selection-hook 'company-box-doc) 1198 | (add-hook 'company-box-hide-hook 'company-box-doc--hide) 1199 | 1200 | ;;;###autoload 1201 | (define-minor-mode company-box-mode 1202 | "Company-box minor mode." 1203 | :group 'company-box 1204 | :lighter " company-box" 1205 | ;; With emacs daemon and: 1206 | ;; `(add-hook 'company-mode-hook 'company-box-mode)' 1207 | ;; `company-box-mode' is called too early to know if we are in a GUI 1208 | (if (and (daemonp) 1209 | (not (frame-parameter nil 'client)) 1210 | company-box-mode) 1211 | (add-hook 'after-make-frame-functions 'company-box--set-mode t t) 1212 | (company-box--set-mode))) 1213 | 1214 | (provide 'company-box) 1215 | ;;; company-box.el ends here 1216 | --------------------------------------------------------------------------------