This repository has been archived by the owner on Mar 31, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
company-emoji.el
225 lines (180 loc) · 8.4 KB
/
company-emoji.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
;;; company-emoji.el --- company-mode backend for emoji
;; Copyright (C) 2018 Alex Dunn
;; Author: Alex Dunn <[email protected]>
;; URL: https://github.com/dunn/company-emoji.git
;; Version: 2.8.0
;; 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.8.0"
"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