225 lines
8.4 KiB
EmacsLisp
225 lines
8.4 KiB
EmacsLisp
;;; company-emoji.el --- company-mode backend for emoji
|
||
|
||
;; Copyright (C) 2018 Alex Dunn
|
||
|
||
;; Author: Alex Dunn <dunn.alex@gmail.com>
|
||
;; URL: https://github.com/dunn/company-emoji.git
|
||
;; Version: 2.5.2
|
||
;; Package-Requires: ((cl-lib "0.5") (company "0.8.0"))
|
||
;; Keywords: emoji company
|
||
;; Prefix: company-emoji
|
||
|
||
;; This program is free software; you can redistribute it and/or modify
|
||
;; it under the terms of the GNU General Public License as published by
|
||
;; the Free Software Foundation, either version 3 of the License, or
|
||
;; (at your option) any later version.
|
||
|
||
;; This program is distributed in the hope that it will be useful,
|
||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
;; GNU General Public License for more details.
|
||
|
||
;; You should have received a copy of the GNU General Public License
|
||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
;;; Commentary:
|
||
|
||
;; company-mode backend providing autocompletion for emoji. 🆒💦
|
||
|
||
;; ## setup
|
||
|
||
;; Add `company-emoji.el` to your load-path, then add something like the
|
||
;; following to your init file:
|
||
|
||
;; ```elisp
|
||
;; (require 'company-emoji)
|
||
;; (add-to-list 'company-backends 'company-emoji)
|
||
;; ```
|
||
|
||
;; After selecting an emoji-word from the completion-list, it will be
|
||
;; replaced by the real unicode emoji (`:cactus:` becomes 🌵, `:cat:`
|
||
;; becomes 🐱, etc.)
|
||
|
||
;; ### emoji font support
|
||
|
||
;; If you’re on Linux, or on Mac OS X and using the Cocoa version of
|
||
;; Emacs (i.e., if built `‐-with-ns`, or `--with-cocoa` using Homebrew),
|
||
;; you’ll need to add something like this to your init file (thanks to
|
||
;; [@syohex](https://github.com/syohex) and
|
||
;; [@waymondo](https://github.com/waymondo)):
|
||
|
||
;; ```elisp
|
||
;; (defun --set-emoji-font (frame)
|
||
;; "Adjust the font settings of FRAME so Emacs can display emoji properly."
|
||
;; (if (eq system-type 'darwin)
|
||
;; ;; For NS/Cocoa
|
||
;; (set-fontset-font t 'symbol (font-spec :family "Apple Color Emoji") frame 'prepend)
|
||
;; ;; For Linux
|
||
;; (set-fontset-font t 'symbol (font-spec :family "Symbola") frame 'prepend)))
|
||
|
||
;; ;; For when Emacs is started in GUI mode:
|
||
;; (--set-emoji-font nil)
|
||
;; ;; Hook for when a frame is created with emacsclient
|
||
;; ;; see https://www.gnu.org/software/emacs/manual/html_node/elisp/Creating-Frames.html
|
||
;; (add-hook 'after-make-frame-functions '--set-emoji-font)
|
||
;; ```
|
||
|
||
;; [Symbola](https://zhm.github.io/symbola/) can be installed with `apt-get`:
|
||
|
||
;; ```sh
|
||
;; apt-get install ttf-ancient-fonts
|
||
;; ```
|
||
|
||
;; **NB:** The `set-fontset-font` function is apparently only available
|
||
;; when Emacs has been compiled with a window system.
|
||
|
||
;; ### custom variables
|
||
|
||
;; #### aliases
|
||
|
||
;; You can add shortcode aliases by modifying `company-emoji-aliases`.
|
||
;; Run `M-x customize-variable [RET] company-emoji-aliases` to bring up
|
||
;; company-emoji’s customization pane, then add or remove aliases to your
|
||
;; taste:
|
||
|
||
;; ```
|
||
;; Hide Company Emoji Aliases:
|
||
;; [INS] [DEL] Symbol: :woman_man_holding_hands:
|
||
;; String: :couple:
|
||
;; [INS]
|
||
;; ```
|
||
|
||
;; (“Symbol” designates the user-defined alias, and “string” designates
|
||
;; the original shortcode you want your alias to mimick.)
|
||
|
||
;; Occasionally new default aliases may be added. If you’re upgrading
|
||
;; and have modified the `company-emoji-aliases` variable, the new
|
||
;; aliases will be ignored; you’ll need to add them manually.
|
||
|
||
;; #### unicode replacement
|
||
|
||
;; By default, `:cat:` is replaced with 🐱 upon completion, but that can
|
||
;; be turned off by setting the variable `company-emoji-insert-unicode`
|
||
;; to `nil`.
|
||
|
||
;; ## contributing
|
||
|
||
;; Contributions are very welcome! But please don’t edit
|
||
;; `company-emoji-list.el` directly: it’s generated by
|
||
;; `build/generate_list.rb`, so you should modify that build script then
|
||
;; run `make company-emoji-list.el`.
|
||
|
||
;;; Code:
|
||
|
||
;; requires
|
||
|
||
(require 'cl-lib)
|
||
(require 'company)
|
||
(require 'company-emoji-list)
|
||
|
||
(defconst company-emoji-version "2.5.1"
|
||
"Current version of company-emoji.")
|
||
|
||
(defconst company-emojis (company-emoji-list-create)
|
||
"Cached list of propertized emojis.")
|
||
|
||
;; customize
|
||
|
||
(defgroup company-emoji nil
|
||
"Company-mode backend for autocompleting emoji"
|
||
:group 'company)
|
||
|
||
(defcustom company-emoji-aliases '((:woman_man_holding_hands: . ":couple:")
|
||
(:-1: . ":thumbsdown:")
|
||
(:+1: . ":thumbsup:"))
|
||
"Alternate shortcodes for emoji."
|
||
:group 'company-emoji
|
||
:type '(alist :key-type symbol :value-type string))
|
||
|
||
(defcustom company-emoji-insert-unicode t
|
||
"Replace the :shortcode: with the real Unicode character upon completion."
|
||
:group 'company-emoji
|
||
:type 'boolean)
|
||
|
||
(defun company-emoji--annotation (s)
|
||
"Return a formatted annotation for completion candidate S."
|
||
(format " %s" (get-text-property 0 :unicode s)))
|
||
|
||
(defun company-emoji--add-aliases (aliases candidates)
|
||
"Add the emoji ALIASES to the list of completion CANDIDATES and return the new list."
|
||
(dolist (elem aliases candidates)
|
||
;; * `aliased` will be nil if the alias alist is somehow
|
||
;; malformed—if there's no second element.
|
||
;;
|
||
;; * `emoji-string` will be nil if the current alias is invalid—if
|
||
;; the shortcode that an alias has been assigned to does not
|
||
;; correspond to any emoji. For example, if you added (:kermit:
|
||
;; . ":toad:") to your list of custom aliases, that would be an
|
||
;; invalid assignment since :toad: is not a real shortcode—we
|
||
;; only have :frog:. As long as this is a valid alias, then
|
||
;; emoji-string is the propertized text that the alias points
|
||
;; to; something like #(":imp:" 0 1 (:unicode "👿"))
|
||
(let* ((aliased (cdr elem))
|
||
(emoji-string (car (member aliased candidates))))
|
||
(if (and aliased emoji-string)
|
||
;; * `new-item` is what will become a new propertized string
|
||
;; that we add to the list of completion candidates. It
|
||
;; starts its life as the string version of the current
|
||
;; alias; from (:man-woman-boy: . ":family:"), the string
|
||
;; assigned to `new-item` would be ":man-woman-boy:"
|
||
;;
|
||
;; * `unicode` is the unicode character to which we want our
|
||
;; alias to point; we retrieve it from `emoji-string`.
|
||
(let ((new-item (symbol-name (car elem)))
|
||
(unicode (get-text-property 0 :unicode emoji-string)))
|
||
;; Propertize the `new-item` string. The string returned
|
||
;; from `symbol-name` already seems to have some properties,
|
||
;; so overwrite them with `set-text-properties', instead of
|
||
;; simply adding a new property with `add-text-property'.
|
||
(set-text-properties 0 1 (list ':unicode unicode) new-item)
|
||
(setq candidates (cons new-item candidates)))))))
|
||
|
||
;;;###autoload
|
||
(defun company-emoji (command &optional arg &rest ignored)
|
||
"Provide a backend for company to complete emoji-words.
|
||
|
||
company.el calls this function, and passes a COMMAND to it that
|
||
depends on the context: 'prefix', 'candidates', 'annotation',
|
||
etc. In some contexts it also passes ARG, which is the list of
|
||
candidates that match what has been typed so far. Sometimes ARG
|
||
is a single candidate, as when COMMAND is 'annotation' or
|
||
'post-completion'. Other arguments are IGNORED."
|
||
|
||
;; First, update the list of candidates by adding the custom
|
||
;; aliases:
|
||
(let ((emoji-list (company-emoji--add-aliases
|
||
company-emoji-aliases
|
||
company-emojis)))
|
||
(cl-case command
|
||
;; 'prefix' has too many meanings in emacs lisp but here we're
|
||
;; specifying what the string we're completing should begin with
|
||
(prefix (company-grab "\:[a-zA-Z0-9-_]*"))
|
||
(candidates
|
||
;; filter based on what's already been typed
|
||
(cl-remove-if-not
|
||
(lambda (c) (string-prefix-p arg c))
|
||
emoji-list))
|
||
;; show the real emoji alongside its name in the completion list
|
||
(annotation (company-emoji--annotation arg))
|
||
;; when we find the emoji we want, replace it with the real emoji
|
||
;; (assuming company-emoji-insert-unicode is set to true)
|
||
(post-completion
|
||
(if company-emoji-insert-unicode
|
||
(progn
|
||
(kill-region (- (point) (length arg)) (point))
|
||
(insert (get-text-property 0 :unicode arg))))))))
|
||
|
||
;;;###autoload
|
||
(defun company-emoji-init ()
|
||
"Add emoji to the company backends."
|
||
(interactive)
|
||
(add-to-list 'company-backends 'company-emoji))
|
||
|
||
(provide 'company-emoji)
|
||
|
||
;;; company-emoji.el ends here
|