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:
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-"))