Subject: Re: bug#16981: 24.3.50; electric-pair-delete-adjacent-pairs broken in c-mode, python-mode, maybe-others

From: [email-masked] (João Távora)
Date: Sat, 05 Apr 2014 12:58:36 +0100

Hi Alan,

Sorry for the delay, I only check emacs-devel regularly, do cc me next
time please if you remember.

> There's something funny going on here.  A minor mode's keymap should
> normally take precedence over the major mode's keymap.  (See the page 
> "Searching Keymaps" in the Elisp manual.)  So why is electric-pair-mode's
> keymap being overridden by CC Mode's here?

You're right, but I can't figure out what. Probably has to do with
remapping and translation. But if it were the other way around, you'd
probably be reporting the bug :-) so it doesn't matter.

>> Perhaps a hook in `backward-delete-char' is in order. Or the other major
>> modes can find other ways to overload the backspace key.
> I would say it's legitimate for a major mode to bind the backspace key, but
> it's more questionable for a minor mode to do the same.  Perhaps the minor
> mode really ought to use defadvice rather than rebinding the key.

Yes, I think so too. Or both can use a (possibly excessively
complicated) system of backspace-related hooks.  Advice would probably
work too, but do we want that in emacs? Stefan, when you suggested the
rebinding originally, was it with any particular concern in mind?

Why not this, just the single `delete-backward-char-before-hook'. Seems
to work. Maybe also add a "don't use this in programs" to
`delete-backward-char'...

=== modified file 'lisp/elec-pair.el'
*** lisp/elec-pair.el	2014-04-04 23:31:02 +0000
--- lisp/elec-pair.el	2014-04-05 11:28:42 +0000
***************
*** 166,176 ****
  quotes or comments.  If lookup fails here, `electric-pair-text-pairs' will
  be considered.")
  
! (defun electric-pair-backward-delete-char (n &optional killflag untabify)
!   "Delete characters backward, and maybe also two adjacent paired delimiters.
! 
! Remaining behavior is given by `backward-delete-char' or, if UNTABIFY is
! non-nil, `backward-delete-char-untabify'."
    (interactive "*p\nP")
    (let* ((prev (char-before))
           (next (char-after))
--- 166,173 ----
  quotes or comments.  If lookup fails here, `electric-pair-text-pairs' will
  be considered.")
  
! (defun electric-pair-delete-pair-maybe (killflag)
!   "Forward-delete pair of soon-to-be-deleted char before point."
    (interactive "*p\nP")
    (let* ((prev (char-before))
           (next (char-after))
***************
*** 184,200 ****
                   electric-pair-delete-adjacent-pairs)
                 (memq syntax '(?\( ?\" ?\$))
                 (eq pair next))
!       (delete-char 1 killflag))
!     (if untabify
!         (backward-delete-char-untabify n killflag)
!         (backward-delete-char n killflag))))
! 
! (defun electric-pair-backward-delete-char-untabify (n &optional killflag)
!   "Delete characters backward, and maybe also two adjacent paired delimiters.
  
! Remaining behavior is given by `backward-delete-char-untabify'."
!   (interactive "*p\nP")
!   (electric-pair-backward-delete-char n killflag t))
  
  (defun electric-pair-conservative-inhibit (char)
    (or
--- 181,189 ----
                   electric-pair-delete-adjacent-pairs)
                 (memq syntax '(?\( ?\" ?\$))
                 (eq pair next))
!       (delete-char 1 killflag))))
  
! (add-hook 'delete-backward-char-before-hook 'electric-pair-delete-pair-maybe)
  
  (defun electric-pair-conservative-inhibit (char)
    (or
***************
*** 546,562 ****
         (memq (car (electric-pair-syntax-info last-command-event))
               '(?\( ?\) ?\" ?\$))))
  
- (defvar electric-pair-mode-map
-   (let ((map (make-sparse-keymap)))
-     (define-key map [remap backward-delete-char-untabify]
-       'electric-pair-backward-delete-char-untabify)
-     (define-key map [remap backward-delete-char]
-       'electric-pair-backward-delete-char)
-     (define-key map [remap delete-backward-char]
-       'electric-pair-backward-delete-char)
-     map)
-   "Keymap used by `electric-pair-mode'.")
- 
  ;;;###autoload
  (define-minor-mode electric-pair-mode
    "Toggle automatic parens pairing (Electric Pair mode).
--- 535,540 ----

=== modified file 'lisp/simple.el'
*** lisp/simple.el	2014-04-02 15:14:50 +0000
--- lisp/simple.el	2014-04-05 11:27:17 +0000
***************
*** 949,954 ****
--- 949,959 ----
  is undefined.  If DELETE is nil, just return the content as a string.
  If anything else, delete the region and return its content as a string.")
  
+ (defvar delete-backward-char-before-hook nil
+   "Hook run just before `delete-backward-char' actually deletes.
+ Each function in this list is passed the KILLFLAG arg to
+ `delete-backward-char' call.")
+ 
  (defun delete-backward-char (n &optional killflag)
    "Delete the previous N characters (following if N is negative).
  If Transient Mark mode is enabled, the mark is active, and N is 1,
***************
*** 984,990 ****
  	   (save-excursion
  	     (insert-char ?\s (- ocol (current-column)) nil))))
  	;; Otherwise, do simple deletion.
! 	(t (delete-char (- n) killflag))))
  
  (defun delete-forward-char (n &optional killflag)
    "Delete the following N characters (previous if N is negative).
--- 989,997 ----
  	   (save-excursion
  	     (insert-char ?\s (- ocol (current-column)) nil))))
  	;; Otherwise, do simple deletion.
! 	(t
!          (run-hook-with-args 'delete-backward-char-before-hook killflag)
!          (delete-char (- n) killflag))))
  
  (defun delete-forward-char (n &optional killflag)
    "Delete the following N characters (previous if N is negative).