emacs-emojify

fork of https://github.com/iqbalansari/emacs-emojify
Log | Files | Refs | LICENSE

commit a905cb1f557aa9c944668c1dd15fd8ba4766314f
parent 553303dda9e1b68b03cf612efceef7fc88fe6e0b
Author: Iqbal Ansari <iqbalansari02@yahoo.com>
Date:   Sun, 22 Nov 2015 21:43:52 +0530

Merge branch 'develop'

Fixes #5

Diffstat:
M.travis.yml | 2+-
Memojify.el | 53++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mtest/emojify-test.el | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 131 insertions(+), 2 deletions(-)

diff --git a/.travis.yml b/.travis.yml @@ -36,7 +36,7 @@ install: - cask install script: - - cask exec ert-runner --reporter ert + - cask exec ert-runner notifications: email: diff --git a/emojify.el b/emojify.el @@ -479,6 +479,14 @@ To understand WINDOW, STRING and POS see the function documentation for ;; Core functions and macros +(defvar emojify-emoji-keymap (let ((map (make-sparse-keymap))) + (define-key map [remap delete-char] #'emojify-delete-emoji-forward) + (define-key map [remap delete-forward-char] #'emojify-delete-emoji-forward) + (define-key map [remap backward-delete-char] #'emojify-delete-emoji-backward) + (define-key map [remap delete-backward-char] #'emojify-delete-emoji-backward) + (define-key map [remap backward-delete-char-untabify] #'emojify-delete-emoji-backward) + map)) + (defun emojify--get-point-left-function (buffer match-beginning match-end) "Create a function that can be executed in point-left hook for emoji text. @@ -490,6 +498,25 @@ mark the start and end of region containing the text." (< new-point match-beginning))) (emojify-redisplay-emojis match-beginning match-end)))) +(defun emojify--find-key-binding-ignoring-emojify-keymap (key) + "Find the binding for given KEY ignoring the text properties at point. + +This is needed since `key-binding' looks up in keymap text property as well +which is not what we want when falling back in `emojify-delete-emoji'" + (let* ((minor-mode-binding (minor-mode-key-binding key)) + (local-binding (local-key-binding key)) + (global-binding (global-key-binding key)) + (key-binding (or minor-mode-binding + local-binding + global-binding))) + (when key-binding + (or (command-remapping key-binding + nil + (seq-filter (lambda (keymap) + (not (equal keymap emojify-emoji-keymap))) + (current-active-maps))) + key-binding)))) + (defun emojify--get-image-display (data) "Get the display text property to display the emoji specified in DATA as an image." (let* ((image-file (expand-file-name (ht-get data "image") @@ -593,6 +620,7 @@ TODO: Skip emojifying if region is already emojified." 'emojify-text match 'emojify-start match-beginning 'emojify-end match-end + 'keymap emojify-emoji-keymap 'point-entered #'emojify-point-entered-function 'help-echo #'emojify-help-function))))))))))) @@ -628,10 +656,33 @@ BEG and END are the beginning and end of the region respectively" 'emojify-text t 'emojify-start t 'emojify-end t - 'help-echo t)))) + 'keymap t + 'help-echo t + 'rear-nonsticky t)))) ;; Setup the next iteration (setq beg emoji-end))))) +(defun emojify-delete-emoji (point) + "Delete emoji at POINT." + (if (get-text-property point 'emojified) + (delete-region (get-text-property point 'emojify-start) + (get-text-property point 'emojify-end)) + (call-interactively (emojify--find-key-binding-ignoring-emojify-keymap (this-command-keys))))) + +(defun emojify-delete-emoji-forward () + "Delete emoji after point." + (interactive) + (emojify-delete-emoji (point))) + +(defun emojify-delete-emoji-backward () + "Delete emoji before point." + (interactive) + (emojify-delete-emoji (1- (point)))) + +;; Integrate with delete-selection-mode +(put 'emojify-delete-emoji-forward 'delete-selection 'supersede) +(put 'emojify-delete-emoji-backward 'delete-selection 'supersede) + (defun emojify-redisplay-emojis (&optional beg end) "Redisplay emojis in region between BEG and END. diff --git a/test/emojify-test.el b/test/emojify-test.el @@ -33,6 +33,23 @@ (should (equal (get-text-property (point) 'emojify-end) (point-max))) (should (equal (get-text-property (point) 'emojify-text) ":smile:")))) +(ert-deftest emojify-tests-simple-unicode-emoji-test () + :tags '(unicode simple) + (emojify-tests-with-emojified-static-buffer "😉" + (emojify-tests-should-be-emojified (point-min)) + (should (equal (get-text-property (point) 'emojify-buffer) (current-buffer))) + (should (equal (get-text-property (point-min) 'emojify-start) (point-min))) + (should (equal (get-text-property (point) 'emojify-end) (point-max))) + (should (equal (get-text-property (point) 'emojify-text) "😉")))) + +(ert-deftest emojify-tests-mixed-emoji-test () + :tags '(core mixed) + (emojify-tests-with-emojified-static-buffer "😉\n:D\nD:\n:smile:" + (emojify-tests-should-be-emojified (point-min)) + (emojify-tests-should-be-emojified (line-beginning-position 2)) + (emojify-tests-should-not-be-emojified (line-beginning-position 3)) + (emojify-tests-should-be-emojified (line-beginning-position 4)))) + (ert-deftest emojify-tests-emojifying-on-comment-uncomment () :tags '(core after-change) (emojify-tests-with-emojified-buffer ":smile:\n:)" @@ -213,6 +230,7 @@ (ert-deftest emojify-tests-multiple-emojis-in-sequence () "See Github issue #6" + :tags '(core contextual) (emojify-tests-with-emojified-static-buffer ":100::smile: :100:a:smile: 🎆😃 @@ -340,6 +358,66 @@ (emojify-tests-should-be-emojified first-emoji-pos) (emojify-tests-should-be-emojified second-emoji-pos))))) +(ert-deftest emojify-tests-electric-delete () + :tags '(electric-delete) + (emojify-tests-with-emojified-buffer "Unicode emoji 😉\nGithub emoji :wink:\nAscii emoji ;)" + (goto-char (line-end-position)) + (let ((final-line-end (get-text-property (1- (point)) 'emojify-start))) + (execute-kbd-macro [backspace]) + (emojify-tests-should-not-be-emojified (line-end-position)) + (should (equal (line-end-position) final-line-end)))) + + (emojify-tests-with-emojified-buffer "Unicode emoji 😉\nGithub emoji :wink:\nAscii emoji ;)" + (goto-char (line-end-position 2)) + (let ((final-line-end (get-text-property (1- (point)) 'emojify-start))) + (execute-kbd-macro [backspace]) + (emojify-tests-should-not-be-emojified (line-end-position)) + (should (equal (line-end-position) final-line-end)))) + + (emojify-tests-with-emojified-buffer "Unicode emoji 😉\nGithub emoji :wink:\nAscii emoji ;)" + (goto-char (line-end-position 3)) + (let ((final-line-end (get-text-property (1- (point)) 'emojify-start))) + (execute-kbd-macro [backspace]) + (emojify-tests-should-not-be-emojified (line-end-position)) + (should (equal (line-end-position) final-line-end)))) + + (emojify-tests-with-emojified-buffer "😉:wink: ;)" + (dotimes (_ 4) + (execute-kbd-macro (kbd "C-d"))) + (should (equal (point-min) (point-max)))) + + (emojify-tests-with-emojified-buffer "😉:wink: ;)" + (goto-char (point-max)) + (dotimes (_ 4) + (execute-kbd-macro [backspace])) + (should (equal (point-min) (point-max)))) + + (emojify-tests-with-emojified-buffer "😉 :smile:" + (goto-char (1+ (point-min))) + (dotimes (_ 3) + (execute-kbd-macro (kbd "C-d"))) + (should (equal (1+ (point-min)) (point-max)))) + + (emojify-tests-with-emojified-buffer "😉:wink: ;)" + "Integration with delsel mode" + (with-mock + (stub message => nil) + (delete-selection-mode +1) + (set-mark-command nil) + (activate-mark) + (goto-char (point-max)) + (exchange-point-and-mark) + (let ((this-command 'emojify-delete-emoji-forward)) + (delete-selection-pre-hook)) + (should (equal (point-min) (point-max)))))) + +(ert-deftest emojify-tests-no-byte-compilation-errors () + :tags '(byte-compilation) + (with-mock + (stub message => nil) + (stub byte-compile-dest-file => "/tmp/emojify.elc") + (should (byte-compile-file (locate-library "emojify.el"))))) + ;; So that tests can be run simply by doing `eval-buffer' (unless noninteractive (ert "^emojify-"))