GNU bug report logs - #33794
26.1; electric-pair-mode breaks auto-newline minor mode of cc-mode

Previous Next

Packages: emacs, cc-mode;

Reported by: bea <at> klebe.blog

Date: Tue, 18 Dec 2018 17:48:02 UTC

Severity: normal

Found in version 26.1

Done: Alan Mackenzie <acm <at> muc.de>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 33794 in the body.
You can then email your comments to 33794 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-gnu-emacs <at> gnu.org:
bug#33794; Package emacs. (Tue, 18 Dec 2018 17:48:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to bea <at> klebe.blog:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Tue, 18 Dec 2018 17:48:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Beatrix Klebe <beeuhtricks <at> gmail.com>
To: bug-gnu-emacs <at> gnu.org
Subject: 26.1; electric-pair-mode breaks auto-newline minor mode of cc-mode
Date: Tue, 18 Dec 2018 12:38:41 -0500
When using cc-mode, turning on electric-pair-mode causes the
auto-newline minor mode to stop inserting newlines where expected. This
is relevant to the formatting of C# code with the Allman/BSD brace style
in particular, though it would be nice if these modes specifically did
work together.

In GNU Emacs 26.1 (build 1, x86_64-apple-darwin14.5.0, NS
appkit-1348.17 Version 10.10.5 (Build 14F2511))
 of 2018-05-30 built on builder10-10.porkrind.org
Windowing system distributor 'Apple', version 10.3.1671
Recent messages:
Saving file /Users/bea/.emacs.d/lisp/dotnet.el...
Wrote /Users/bea/.emacs.d/lisp/dotnet.el
; expected
Undo!
; expected
Undo! [2 times]
; expected
Auto-saving...
; expected [2 times]
Making completion list...

Configured using:
 'configure --with-ns '--enable-locallisppath=/Library/Application
 Support/Emacs/${version}/site-lisp:/Library/Application
 Support/Emacs/site-lisp' --with-modules'

Configured features:
NOTIFY ACL GNUTLS LIBXML2 ZLIB TOOLKIT_SCROLL_BARS NS MODULES THREADS

Important settings:
  value of $LANG: en_US.UTF-8
  locale-coding-system: utf-8-unix

Major mode: C#//la

Minor modes in effect:
  smartparens-global-strict-mode: t
  smartparens-strict-mode: t
  smartparens-mode: t
  diff-auto-refine-mode: t
  projectile-mode: t
  omnisharp-mode: t
  rainbow-delimiters-mode: t
  delete-selection-mode: t
  global-flycheck-mode: t
  flycheck-mode: t
  global-company-mode: t
  company-mode: t
  global-hl-line-mode: t
  global-display-line-numbers-mode: t
  display-line-numbers-mode: t
  override-global-mode: t
  tooltip-mode: t
  global-eldoc-mode: t
  eldoc-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  size-indication-mode: t
  column-number-mode: t
  line-number-mode: t
  transient-mark-mode: t

Load-path shadows:
None found.

Features:
(shadow sort mail-extr emacsbug sendmail smartparens-config warnings
smartparens-text smartparens-ruby smartparens autoload radix-tree
lisp-mnt tar-mode mm-archive message format-spec rfc822 mml mml-sec epa
derived epg gnus-util rmail rmail-loaddefs mailabbrev gmm-utils
mailheader mm-decode mm-bodies mm-encode mail-utils network-stream
starttls url-http tls gnutls mail-parse rfc2231 rfc2047 rfc2045 mm-util
ietf-drums mail-prsvr url-gw nsm rmc puny url-cache url-auth url
url-proxy url-privacy url-expand url-methods url-history url-cookie
url-domsuf url-util mailcap pp cus-edit cus-start cus-load wid-edit
vc-git diff-mode projectile grep ibuf-ext ibuffer ibuffer-loaddefs
omnisharp omnisharp-unit-test-actions omnisharp-code-structure
omnisharp-server-installation omnisharp-format-actions
omnisharp-solution-actions omnisharp-helm-integration
omnisharp-navigation-actions omnisharp-current-symbol-actions
omnisharp-auto-complete-actions omnisharp-server-actions
omnisharp-http-utils omnisharp-utils omnisharp-server-management
omnisharp-settings f s popup dired dired-loaddefs thingatpt ido
csharp-mode imenu compile comint ansi-color cc-mode cc-fonts cc-guess
cc-menus cc-cmds cc-styles cc-align cc-engine cc-vars cc-defs
parinfer-ext parinfer ediff-merg ediff-wind ediff-diff ediff-mult
ediff-help ediff-init ediff-util ediff mode-local parinferlib
rainbow-delimiters windows-config macos-config exec-path-from-shell
org-mode-config development proof-general-config dotnet elec-pair ocaml
backup editor delsel flycheck-config flycheck json map find-func rx
subr-x company-config delight advice company-oddmuse company-keywords
company-etags etags xref project ring company-gtags company-dabbrev-code
company-dabbrev company-files company-capf company-cmake company-xcode
company-clang company-semantic company-eclim company-template
company-bbdb company edmacro kmacro pcase ui hl-line
display-line-numbers zenburn-theme package-config auto-package-update
dash use-package use-package-ensure use-package-delight
use-package-diminish use-package-bind-key bind-key easy-mmode
use-package-core cl-extra help-mode finder-inf proof-site
proof-autoloads pg-vars info package easymenu epg-config url-handlers
url-parse auth-source cl-seq eieio eieio-core cl-macs eieio-loaddefs
password-cache url-vars seq byte-opt bytecomp byte-compile cconv cl gv
cl-loaddefs cl-lib time-date tooltip eldoc electric uniquify ediff-hook
vc-hooks lisp-float-type mwheel term/ns-win ns-win ucs-normalize
mule-util term/common-win tool-bar dnd fontset image regexp-opt fringe
tabulated-list replace newcomment text-mode elisp-mode lisp-mode
prog-mode register page menu-bar rfn-eshadow isearch timer select
scroll-bar mouse jit-lock font-lock syntax facemenu font-core
term/tty-colors frame cl-generic cham georgian utf-8-lang misc-lang
vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms cp51932
hebrew greek romanian slovak czech european ethiopic indian cyrillic
chinese composite charscript charprop case-table epa-hook jka-cmpr-hook
help simple abbrev obarray minibuffer cl-preloaded nadvice loaddefs
button faces cus-face macroexp files text-properties overlay sha1 md5
base64 format env code-pages mule custom widget hashtable-print-readable
backquote kqueue cocoa ns multi-tty make-network-process emacs)

Memory information:
((conses 16 500415 57879)
 (symbols 48 41866 532)
 (miscs 40 198 1263)
 (strings 32 116702 6337)
 (string-bytes 1 3303823)
 (vectors 16 61571)
 (vector-slots 8 1021437 30984)
 (floats 8 135 577)
 (intervals 56 1409 585)
 (buffers 992 21))




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Fri, 21 Dec 2018 13:49:01 GMT) Full text and rfc822 format available.

Message #8 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: bea <at> klebe.blog
Cc: 33794 <at> debbugs.gnu.org,
 João Távora <joaotavora <at> gmail.com>
Subject: Re: bug#33794: 26.1;
 electric-pair-mode breaks auto-newline minor mode of cc-mode
Date: 21 Dec 2018 13:48:29 -0000
Hello, Beatrix.

In article <mailman.5894.1545155289.1284.bug-gnu-emacs <at> gnu.org> you wrote:
> When using cc-mode, turning on electric-pair-mode causes the
> auto-newline minor mode to stop inserting newlines where expected. This
> is relevant to the formatting of C# code with the Allman/BSD brace style
> in particular, though it would be nice if these modes specifically did
> work together.

Yes.  What is happening, from the viewpoint of CC Mode, is that on
inserting a {, electric-pair-mode is prematurely inserting its }, before
the processing for the { is complete.  Also, due to the way } gets
inserted, the CC Mode processing for the } isn't done at all.

@João: I think electric pair mode is intended to simulate the manual
insertion of a matching paren, etc., when a paren, etc., is typed.

Would it therefore be possible, rather than having a crude insertion on
post-self-insert-hook, to use something like post-command-hook to allow
the insertion of the { first to complete?  Then, rather than using the
brutal self-insert-command for } in electric-pair--insert, use the
command to which the key } is bound?  This should allow CC Mode's
auto-newline facility to work, and also more closely simulate the manual
insertion of the closing delimiter.

> In GNU Emacs 26.1 (build 1, x86_64-apple-darwin14.5.0, NS
> appkit-1348.17 Version 10.10.5 (Build 14F2511))
>  of 2018-05-30 built on builder10-10.porkrind.org
> Windowing system distributor 'Apple', version 10.3.1671
> Recent messages:
> Saving file /Users/bea/.emacs.d/lisp/dotnet.el...
> Wrote /Users/bea/.emacs.d/lisp/dotnet.el
> ; expected
> Undo!
> ; expected
> Undo! [2 times]
> ; expected
> Auto-saving...
> ; expected [2 times]
> Making completion list...

-- 
Alan Mackenzie (Nuremberg, Germany).





Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Fri, 21 Dec 2018 13:58:01 GMT) Full text and rfc822 format available.

Message #11 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: João Távora <joaotavora <at> gmail.com>
To: Alan Mackenzie <acm <at> muc.de>
Cc: bea <at> klebe.blog, 33794 <at> debbugs.gnu.org,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Fri, 21 Dec 2018 13:57:21 +0000
[Message part 1 (text/plain, inline)]
On Fri, Dec 21, 2018 at 1:48 PM Alan Mackenzie <acm <at> muc.de> wrote:

> Hello, Beatrix.
>
> In article <mailman.5894.1545155289.1284.bug-gnu-emacs <at> gnu.org> you wrote:
> > When using cc-mode, turning on electric-pair-mode causes the
> > auto-newline minor mode to stop inserting newlines where expected. This
> > is relevant to the formatting of C# code with the Allman/BSD brace style
> > in particular, though it would be nice if these modes specifically did
> > work together.
>
> Yes.  What is happening, from the viewpoint of CC Mode, is that on
> inserting a {, electric-pair-mode is prematurely inserting its }, before
> the processing for the { is complete.  Also, due to the way } gets
> inserted, the CC Mode processing for the } isn't done at all.
>
> @João: I think electric pair mode is intended to simulate the manual
> insertion of a matching paren, etc., when a paren, etc., is typed.
>
> Would it therefore be possible, rather than having a crude insertion on
> post-self-insert-hook, to use something like post-command-hook to allow
> the insertion of the { first to complete?  Then, rather than using the
> brutal self-insert-command for } in electric-pair--insert, use the
> command to which the key } is bound?  This should allow CC Mode's
> auto-newline facility to work, and also more closely simulate the manual
> insertion of the closing delimiter.


I don't know.  We better ask Stefan (CC'ed) who I believe designed the
original strategy of inserting closing delimiters in the previous
electric-pair-mode. That didn't change in my redesign.

FWIW, I think cc-mode should rather use post-self-insert-hook instead
of redefining commands for keys whose expected behaviour is
(with minor variations presumably covered by abundant hookage)
self-insertion.  If you place your specific cc-mode processing late
enough in the hook then its insertion will be "complete" for all
practical purposes.

João
[Message part 2 (text/html, inline)]

Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Fri, 21 Dec 2018 14:13:02 GMT) Full text and rfc822 format available.

Message #14 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> IRO.UMontreal.CA>
To: João Távora <joaotavora <at> gmail.com>
Cc: Alan Mackenzie <acm <at> muc.de>, bea <at> klebe.blog, 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1;
 electric-pair-mode breaks auto-newline minor mode of cc-mode
Date: Fri, 21 Dec 2018 09:12:49 -0500
>> Yes.  What is happening, from the viewpoint of CC Mode, is that on
>> inserting a {, electric-pair-mode is prematurely inserting its }, before
>> the processing for the { is complete.

Since it's done from post-self-insert-hook, it's done at the very end of
inserting { so I'm not sure what you mean by "before the processing for
the { is complete".

>> Also, due to the way } gets inserted, the CC Mode processing for
>> the } isn't done at all.

I think you meant "due to the way CC-Mode hooks itself into the }
processing, ..." ;-)

>> Would it therefore be possible, rather than having a crude insertion on
>> post-self-insert-hook, to use something like post-command-hook to allow
>> the insertion of the { first to complete?  Then, rather than using the
>> brutal self-insert-command for } in electric-pair--insert, use the
>> command to which the key } is bound?

Talking about brutal: how could electric-pair-mode run whichever command
is bound to } without taking the risk of running a much more brutal
command than one that inserts a character?

> FWIW, I think cc-mode should rather use post-self-insert-hook instead
> of redefining commands for keys whose expected behaviour is
> (with minor variations presumably covered by abundant hookage)
> self-insertion.

IIRC it should be able to just use electric-layout-mode for that (tho
maybe electric-layout's featureset doesn't currently cover 100% that of
CC-mode's auto-newline, in which case it would be nice to extend
electric-layout accordingly).

For things like electric-pair, electric-indent, and electric-layout to
work correctly together, they need to agree on some convention.

Note that CC-mode can also side-step that convention and use `insert`
instead of self-insert-command.


        Stefan




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Fri, 21 Dec 2018 16:01:02 GMT) Full text and rfc822 format available.

Message #17 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Beatrix Klebe <beeuhtricks <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: Alan Mackenzie <acm <at> muc.de>, "Mx. Beatrix Klebe" <bea <at> klebe.blog>,
 João Távora <joaotavora <at> gmail.com>, 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Fri, 21 Dec 2018 11:00:10 -0500
I believe I saw your Stack Overflow answer about this while searching
for the solution. electric-layout-mode works with some quirks, such as
that if you put a space after parens in a function definition, the
space gets carried on to the newline with that method, which is a bit
annoying. What would be ideal, and what I'm looking for, is to get
auto-pairing of brackets with braces being placed where they should be
automatically and the insertion point getting put in between them at
the correct indent level, such as what happens with Visual Studio, or
Visual Studio Code, or several other editors with this functionality.
Perhaps it is not emacslike to have such behavior be totally
automated, but I am used to it and finds it decreases my ordinary
levels of frustration when working with verbose and imperative
languages. I am currently trying to write some insert specifiers for
smartparens to do this, but it is proving more difficult to find an
elegant solution than I had expected.

On Fri, Dec 21, 2018 at 10:54 AM Stefan Monnier
<monnier <at> iro.umontreal.ca> wrote:
>
> >> Yes.  What is happening, from the viewpoint of CC Mode, is that on
> >> inserting a {, electric-pair-mode is prematurely inserting its }, before
> >> the processing for the { is complete.
>
> Since it's done from post-self-insert-hook, it's done at the very end of
> inserting { so I'm not sure what you mean by "before the processing for
> the { is complete".
>
> >> Also, due to the way } gets inserted, the CC Mode processing for
> >> the } isn't done at all.
>
> I think you meant "due to the way CC-Mode hooks itself into the }
> processing, ..." ;-)
>
> >> Would it therefore be possible, rather than having a crude insertion on
> >> post-self-insert-hook, to use something like post-command-hook to allow
> >> the insertion of the { first to complete?  Then, rather than using the
> >> brutal self-insert-command for } in electric-pair--insert, use the
> >> command to which the key } is bound?
>
> Talking about brutal: how could electric-pair-mode run whichever command
> is bound to } without taking the risk of running a much more brutal
> command than one that inserts a character?
>
> > FWIW, I think cc-mode should rather use post-self-insert-hook instead
> > of redefining commands for keys whose expected behaviour is
> > (with minor variations presumably covered by abundant hookage)
> > self-insertion.
>
> IIRC it should be able to just use electric-layout-mode for that (tho
> maybe electric-layout's featureset doesn't currently cover 100% that of
> CC-mode's auto-newline, in which case it would be nice to extend
> electric-layout accordingly).
>
> For things like electric-pair, electric-indent, and electric-layout to
> work correctly together, they need to agree on some convention.
>
> Note that CC-mode can also side-step that convention and use `insert`
> instead of self-insert-command.
>
>
>         Stefan




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Fri, 21 Dec 2018 18:50:02 GMT) Full text and rfc822 format available.

Message #20 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: João Távora <joaotavora <at> gmail.com>
To: Beatrix Klebe <beeuhtricks <at> gmail.com>
Cc: Alan Mackenzie <acm <at> muc.de>, bea <at> klebe.blog,
 Stefan Monnier <monnier <at> iro.umontreal.ca>, 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1;
 electric-pair-mode breaks auto-newline minor mode of cc-mode
Date: Fri, 21 Dec 2018 18:49:34 +0000
Beatrix Klebe <beeuhtricks <at> gmail.com> writes:

> I believe I saw your Stack Overflow answer about this while searching
> for the solution. electric-layout-mode works with some quirks, such as
> that if you put a space after parens in a function definition, the
> space gets carried on to the newline with that method, which is a bit
> annoying. What would be ideal, and what I'm looking for, is to get
> auto-pairing of brackets with braces being placed where they should be
> automatically and the insertion point getting put in between them at
> the correct indent level, such as what happens with Visual Studio, or
> Visual Studio Code, or several other editors with this functionality.
> Perhaps it is not emacslike to have such behavior be totally
> automated, but I am used to it and finds it decreases my ordinary
> levels of frustration when working with verbose and imperative
> languages. I am currently trying to write some insert specifiers for
> smartparens to do this, but it is proving more difficult to find an
> elegant solution than I had expected.

It is quite emacslike (though maybe not activated by default): you just
have to report the bugs to the Emacs developers as efficiently as
possible.

1. Though Alan possibly has already, I still cannot understand the
   original problem.  Can you start by describing what the buffer looked
   like before, what you did, what it looked like afterwards, and what
   you expected it to look like?  If possible start with a clean Emacs
   -Q recpe.

2. I have experimented with nicer-playing like alternatives like
   electric-layout-mode.  I came across a few quirks myself (though I'm
   not sure if they are the same as yours). So I prepared a patch (in
   branch scratch/fix-33794-extend-electric-layout-mode) and attached
   it after the sig.

After loading this patch, in a simple Emacs -Q the configuration:

   (electric-pair-mode)
   (electric-layout-mode)
    
   (add-hook 'c-mode-hook
          (lambda ()
            (setq-local electric-layout-rules
                        '((?\{ . after)
                          (?\{ . after-stay)))))

And, when visiting a C file, if I press `{' I get the expected
pair+layout+indent behaviour.  Sor example opening a brace after
int main () gives me:

    int main () {
        <cursor here>
    }

I, like Stefan, think cc-mode could/should set electric-layout-rules
buffer-locally to reflect whatever c-style the user has selected.

Thanks,
João

PS: Also, can you link to the the relevant to the stack overflow answer you
mentioned?

commit ab036bdedbb49ecc96d550b5e883e43bb03eaccc
Author: João Távora <joaotavora <at> gmail.com>
Date:   Fri Dec 21 18:00:08 2018 +0000

    Extend electric-layout-mode to handle more complex layouts
    
    Also, have it play nice with electric-pair-mode.
    
    Multiple matching entries in `electric-layout-rules' are executed in
    order of appearance.  When inserting a newline in the 'after-stay
    rule, ensure electric-pair-open-newline-between-pairs is nil.
    
    Arguably the logic behind electric-pair-open-newline-between-pairs
    should be moved to electric-layout-mode, but the current rule-matching
    engine doesn't allow for it.  The current solution seems to be good
    enough for the situations reported in bug#33794.
    
    * lisp/electric.el (electric-layout-rules): Adjust docstring.
    (electric-layout-post-self-insert-function): Loop through rules.  Bind
    electric-pair-open-newline-between-pairs to nil when handling
    after-stay.

diff --git a/lisp/electric.el b/lisp/electric.el
index 6dbf46b80c..6a307a49b9 100644
--- a/lisp/electric.el
+++ b/lisp/electric.el
@@ -370,38 +370,43 @@ electric-layout-rules
 
 The symbols specify where in relation to CHAR the newline
 character(s) should be inserted. `after-stay' means insert a
-newline after CHAR but stay in the same place.")
+newline after CHAR but stay in the same place.
+
+If multiple rules match, they are all executed in order of
+appearance.")
 
 (defun electric-layout-post-self-insert-function ()
-  (let* ((rule (cdr (assq last-command-event electric-layout-rules)))
-         pos)
-    (when (and rule
-               (setq pos (electric--after-char-pos))
+  (let (pos)
+    (when (and (setq pos (electric--after-char-pos))
                ;; Not in a string or comment.
                (not (nth 8 (save-excursion (syntax-ppss pos)))))
-      (let ((end (point-marker))
-            (sym (if (functionp rule) (funcall rule) rule)))
-        (set-marker-insertion-type end (not (eq sym 'after-stay)))
-        (goto-char pos)
-        (pcase sym
-          ;; FIXME: we used `newline' down here which called
-          ;; self-insert-command and ran post-self-insert-hook recursively.
-          ;; It happened to make electric-indent-mode work automatically with
-          ;; electric-layout-mode (at the cost of re-indenting lines
-          ;; multiple times), but I'm not sure it's what we want.
-          ;;
-          ;; FIXME: check eolp before inserting \n?
-          ('before (goto-char (1- pos)) (skip-chars-backward " \t")
-                   (unless (bolp) (insert "\n")))
-          ('after  (insert "\n"))
-          ('after-stay (save-excursion
-                         (let ((electric-layout-rules nil))
-                           (newline 1 t))))
-          ('around (save-excursion
-                     (goto-char (1- pos)) (skip-chars-backward " \t")
-                     (unless (bolp) (insert "\n")))
-                   (insert "\n")))      ; FIXME: check eolp before inserting \n?
-        (goto-char end)))))
+      (goto-char pos)
+      (dolist (rule electric-layout-rules)
+        (when (eq last-command-event (car rule))
+          (let* ((end (point-marker))
+                 (rule (cdr rule))
+                 (sym (if (functionp rule) (funcall rule) rule)))
+            (set-marker-insertion-type end (not (eq sym 'after-stay)))
+            (pcase sym
+              ;; FIXME: we used `newline' down here which called
+              ;; self-insert-command and ran post-self-insert-hook recursively.
+              ;; It happened to make electric-indent-mode work automatically with
+              ;; electric-layout-mode (at the cost of re-indenting lines
+              ;; multiple times), but I'm not sure it's what we want.
+              ;;
+              ;; FIXME: check eolp before inserting \n?
+              ('before (goto-char (1- pos)) (skip-chars-backward " \t")
+                       (unless (bolp) (insert "\n")))
+              ('after  (insert "\n"))
+              ('after-stay (save-excursion
+                             (let ((electric-layout-rules nil)
+                                   (electric-pair-open-newline-between-pairs nil))
+                               (newline 1 t))))
+              ('around (save-excursion
+                         (goto-char (1- pos)) (skip-chars-backward " \t")
+                         (unless (bolp) (insert "\n")))
+                       (insert "\n")))      ; FIXME: check eolp before inserting \n?
+            (goto-char end)))))))
 
 (put 'electric-layout-post-self-insert-function 'priority  40)
 




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Fri, 21 Dec 2018 19:07:02 GMT) Full text and rfc822 format available.

Message #23 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Beatrix Klebe <beeuhtricks <at> gmail.com>
To: João Távora <joaotavora <at> gmail.com>
Cc: Alan Mackenzie <acm <at> muc.de>, "Mx. Beatrix Klebe" <bea <at> klebe.blog>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>, 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Fri, 21 Dec 2018 14:06:34 -0500
Here's the link, I believe it was Stefan that answered it:
https://emacs.stackexchange.com/questions/2837/automatically-formatting-brackets/2853#2853

I have tried this with emacs -Q and it does not fix the issue, which
is as follows.

Ordinarily in cc-mode when you have auto-newline-mode activated, and
as far as I can tell, a cc-mode configuration that supports it, (which
csharp-mode contains), the following happens when opening a block
(pipe is the cursor):

void Main() {| // opening bracket is typed

becomes

void Main
{
    |

when c-toggle-auto-newline is activated. However, if you also want
your braces automatically paired, with electric-pair-mode, instead the
following occurs:

void Main() {| // opening bracket is typed

void Main() {|} // electric-pair-mode closes the open bracket, but
auto-newline-mode does not appear to do anything.

void Main() {
    |
} // user hits return, inserting the cursor at the correct indent
level, but leaving the opening brace where it is.

The ideal/desired behavior is:

void Main() {| // opening bracket is typed

void Main()
{
    |
} // user hits return key, electric-pair-mode pairs up the brackets,
and auto-newline-mode formats the braces correctly

It would also probably suffice to format with the newline before
hitting enter as well, although I think I prefer hitting enter to open
the block. I'm quite curious as to the internals of these formatting
systems and would be happy to help with a fix/feature if that would be
desired, I am mostly an OCaml programmer but C# is my day job and I've
just recently gotten deeper into Emacs Lisp.

On Fri, Dec 21, 2018 at 1:49 PM João Távora <joaotavora <at> gmail.com> wrote:
>
> Beatrix Klebe <beeuhtricks <at> gmail.com> writes:
>
> > I believe I saw your Stack Overflow answer about this while searching
> > for the solution. electric-layout-mode works with some quirks, such as
> > that if you put a space after parens in a function definition, the
> > space gets carried on to the newline with that method, which is a bit
> > annoying. What would be ideal, and what I'm looking for, is to get
> > auto-pairing of brackets with braces being placed where they should be
> > automatically and the insertion point getting put in between them at
> > the correct indent level, such as what happens with Visual Studio, or
> > Visual Studio Code, or several other editors with this functionality.
> > Perhaps it is not emacslike to have such behavior be totally
> > automated, but I am used to it and finds it decreases my ordinary
> > levels of frustration when working with verbose and imperative
> > languages. I am currently trying to write some insert specifiers for
> > smartparens to do this, but it is proving more difficult to find an
> > elegant solution than I had expected.
>
> It is quite emacslike (though maybe not activated by default): you just
> have to report the bugs to the Emacs developers as efficiently as
> possible.
>
> 1. Though Alan possibly has already, I still cannot understand the
>    original problem.  Can you start by describing what the buffer looked
>    like before, what you did, what it looked like afterwards, and what
>    you expected it to look like?  If possible start with a clean Emacs
>    -Q recpe.
>
> 2. I have experimented with nicer-playing like alternatives like
>    electric-layout-mode.  I came across a few quirks myself (though I'm
>    not sure if they are the same as yours). So I prepared a patch (in
>    branch scratch/fix-33794-extend-electric-layout-mode) and attached
>    it after the sig.
>
> After loading this patch, in a simple Emacs -Q the configuration:
>
>    (electric-pair-mode)
>    (electric-layout-mode)
>
>    (add-hook 'c-mode-hook
>           (lambda ()
>             (setq-local electric-layout-rules
>                         '((?\{ . after)
>                           (?\{ . after-stay)))))
>
> And, when visiting a C file, if I press `{' I get the expected
> pair+layout+indent behaviour.  Sor example opening a brace after
> int main () gives me:
>
>     int main () {
>         <cursor here>
>     }
>
> I, like Stefan, think cc-mode could/should set electric-layout-rules
> buffer-locally to reflect whatever c-style the user has selected.
>
> Thanks,
> João
>
> PS: Also, can you link to the the relevant to the stack overflow answer you
> mentioned?
>
> commit ab036bdedbb49ecc96d550b5e883e43bb03eaccc
> Author: João Távora <joaotavora <at> gmail.com>
> Date:   Fri Dec 21 18:00:08 2018 +0000
>
>     Extend electric-layout-mode to handle more complex layouts
>
>     Also, have it play nice with electric-pair-mode.
>
>     Multiple matching entries in `electric-layout-rules' are executed in
>     order of appearance.  When inserting a newline in the 'after-stay
>     rule, ensure electric-pair-open-newline-between-pairs is nil.
>
>     Arguably the logic behind electric-pair-open-newline-between-pairs
>     should be moved to electric-layout-mode, but the current rule-matching
>     engine doesn't allow for it.  The current solution seems to be good
>     enough for the situations reported in bug#33794.
>
>     * lisp/electric.el (electric-layout-rules): Adjust docstring.
>     (electric-layout-post-self-insert-function): Loop through rules.  Bind
>     electric-pair-open-newline-between-pairs to nil when handling
>     after-stay.
>
> diff --git a/lisp/electric.el b/lisp/electric.el
> index 6dbf46b80c..6a307a49b9 100644
> --- a/lisp/electric.el
> +++ b/lisp/electric.el
> @@ -370,38 +370,43 @@ electric-layout-rules
>
>  The symbols specify where in relation to CHAR the newline
>  character(s) should be inserted. `after-stay' means insert a
> -newline after CHAR but stay in the same place.")
> +newline after CHAR but stay in the same place.
> +
> +If multiple rules match, they are all executed in order of
> +appearance.")
>
>  (defun electric-layout-post-self-insert-function ()
> -  (let* ((rule (cdr (assq last-command-event electric-layout-rules)))
> -         pos)
> -    (when (and rule
> -               (setq pos (electric--after-char-pos))
> +  (let (pos)
> +    (when (and (setq pos (electric--after-char-pos))
>                 ;; Not in a string or comment.
>                 (not (nth 8 (save-excursion (syntax-ppss pos)))))
> -      (let ((end (point-marker))
> -            (sym (if (functionp rule) (funcall rule) rule)))
> -        (set-marker-insertion-type end (not (eq sym 'after-stay)))
> -        (goto-char pos)
> -        (pcase sym
> -          ;; FIXME: we used `newline' down here which called
> -          ;; self-insert-command and ran post-self-insert-hook recursively.
> -          ;; It happened to make electric-indent-mode work automatically with
> -          ;; electric-layout-mode (at the cost of re-indenting lines
> -          ;; multiple times), but I'm not sure it's what we want.
> -          ;;
> -          ;; FIXME: check eolp before inserting \n?
> -          ('before (goto-char (1- pos)) (skip-chars-backward " \t")
> -                   (unless (bolp) (insert "\n")))
> -          ('after  (insert "\n"))
> -          ('after-stay (save-excursion
> -                         (let ((electric-layout-rules nil))
> -                           (newline 1 t))))
> -          ('around (save-excursion
> -                     (goto-char (1- pos)) (skip-chars-backward " \t")
> -                     (unless (bolp) (insert "\n")))
> -                   (insert "\n")))      ; FIXME: check eolp before inserting \n?
> -        (goto-char end)))))
> +      (goto-char pos)
> +      (dolist (rule electric-layout-rules)
> +        (when (eq last-command-event (car rule))
> +          (let* ((end (point-marker))
> +                 (rule (cdr rule))
> +                 (sym (if (functionp rule) (funcall rule) rule)))
> +            (set-marker-insertion-type end (not (eq sym 'after-stay)))
> +            (pcase sym
> +              ;; FIXME: we used `newline' down here which called
> +              ;; self-insert-command and ran post-self-insert-hook recursively.
> +              ;; It happened to make electric-indent-mode work automatically with
> +              ;; electric-layout-mode (at the cost of re-indenting lines
> +              ;; multiple times), but I'm not sure it's what we want.
> +              ;;
> +              ;; FIXME: check eolp before inserting \n?
> +              ('before (goto-char (1- pos)) (skip-chars-backward " \t")
> +                       (unless (bolp) (insert "\n")))
> +              ('after  (insert "\n"))
> +              ('after-stay (save-excursion
> +                             (let ((electric-layout-rules nil)
> +                                   (electric-pair-open-newline-between-pairs nil))
> +                               (newline 1 t))))
> +              ('around (save-excursion
> +                         (goto-char (1- pos)) (skip-chars-backward " \t")
> +                         (unless (bolp) (insert "\n")))
> +                       (insert "\n")))      ; FIXME: check eolp before inserting \n?
> +            (goto-char end)))))))
>
>  (put 'electric-layout-post-self-insert-function 'priority  40)
>




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Fri, 21 Dec 2018 19:22:02 GMT) Full text and rfc822 format available.

Message #26 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: João Távora <joaotavora <at> gmail.com>
To: bea <at> klebe.blog
Cc: Alan Mackenzie <acm <at> muc.de>, Stefan Monnier <monnier <at> iro.umontreal.ca>,
 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Fri, 21 Dec 2018 19:20:38 +0000
[Message part 1 (text/plain, inline)]
Hi Beatrix,

The solution I propose involves introducing the hotpatch I attached to fix
electric-layout-mode in your emacs, so I wouldn't expect it to work if you
haven't done that.

Do you know how to do it?

Though Alan will probably suggest otherwise, I'd also steer away from
c-specific functionality and keep to the triad electric-indent-mode,
electric-pair-mode and electric-indent-mode, at least while we try to
extend/fix these modes to accommodate your needs.

After such a solution is evaluated, you can select to keep it or move to
something else.

João

On Fri, Dec 21, 2018, 19:06 Beatrix Klebe <beeuhtricks <at> gmail.com wrote:

> Here's the link, I believe it was Stefan that answered it:
>
> https://emacs.stackexchange.com/questions/2837/automatically-formatting-brackets/2853#2853
>
> I have tried this with emacs -Q and it does not fix the issue, which
> is as follows.
>
> Ordinarily in cc-mode when you have auto-newline-mode activated, and
> as far as I can tell, a cc-mode configuration that supports it, (which
> csharp-mode contains), the following happens when opening a block
> (pipe is the cursor):
>
> void Main() {| // opening bracket is typed
>
> becomes
>
> void Main
> {
>     |
>
> when c-toggle-auto-newline is activated. However, if you also want
> your braces automatically paired, with electric-pair-mode, instead the
> following occurs:
>
> void Main() {| // opening bracket is typed
>
> void Main() {|} // electric-pair-mode closes the open bracket, but
> auto-newline-mode does not appear to do anything.
>
> void Main() {
>     |
> } // user hits return, inserting the cursor at the correct indent
> level, but leaving the opening brace where it is.
>
> The ideal/desired behavior is:
>
> void Main() {| // opening bracket is typed
>
> void Main()
> {
>     |
> } // user hits return key, electric-pair-mode pairs up the brackets,
> and auto-newline-mode formats the braces correctly
>
> It would also probably suffice to format with the newline before
> hitting enter as well, although I think I prefer hitting enter to open
> the block. I'm quite curious as to the internals of these formatting
> systems and would be happy to help with a fix/feature if that would be
> desired, I am mostly an OCaml programmer but C# is my day job and I've
> just recently gotten deeper into Emacs Lisp.
>
> On Fri, Dec 21, 2018 at 1:49 PM João Távora <joaotavora <at> gmail.com> wrote:
> >
> > Beatrix Klebe <beeuhtricks <at> gmail.com> writes:
> >
> > > I believe I saw your Stack Overflow answer about this while searching
> > > for the solution. electric-layout-mode works with some quirks, such as
> > > that if you put a space after parens in a function definition, the
> > > space gets carried on to the newline with that method, which is a bit
> > > annoying. What would be ideal, and what I'm looking for, is to get
> > > auto-pairing of brackets with braces being placed where they should be
> > > automatically and the insertion point getting put in between them at
> > > the correct indent level, such as what happens with Visual Studio, or
> > > Visual Studio Code, or several other editors with this functionality.
> > > Perhaps it is not emacslike to have such behavior be totally
> > > automated, but I am used to it and finds it decreases my ordinary
> > > levels of frustration when working with verbose and imperative
> > > languages. I am currently trying to write some insert specifiers for
> > > smartparens to do this, but it is proving more difficult to find an
> > > elegant solution than I had expected.
> >
> > It is quite emacslike (though maybe not activated by default): you just
> > have to report the bugs to the Emacs developers as efficiently as
> > possible.
> >
> > 1. Though Alan possibly has already, I still cannot understand the
> >    original problem.  Can you start by describing what the buffer looked
> >    like before, what you did, what it looked like afterwards, and what
> >    you expected it to look like?  If possible start with a clean Emacs
> >    -Q recpe.
> >
> > 2. I have experimented with nicer-playing like alternatives like
> >    electric-layout-mode.  I came across a few quirks myself (though I'm
> >    not sure if they are the same as yours). So I prepared a patch (in
> >    branch scratch/fix-33794-extend-electric-layout-mode) and attached
> >    it after the sig.
> >
> > After loading this patch, in a simple Emacs -Q the configuration:
> >
> >    (electric-pair-mode)
> >    (electric-layout-mode)
> >
> >    (add-hook 'c-mode-hook
> >           (lambda ()
> >             (setq-local electric-layout-rules
> >                         '((?\{ . after)
> >                           (?\{ . after-stay)))))
> >
> > And, when visiting a C file, if I press `{' I get the expected
> > pair+layout+indent behaviour.  Sor example opening a brace after
> > int main () gives me:
> >
> >     int main () {
> >         <cursor here>
> >     }
> >
> > I, like Stefan, think cc-mode could/should set electric-layout-rules
> > buffer-locally to reflect whatever c-style the user has selected.
> >
> > Thanks,
> > João
> >
> > PS: Also, can you link to the the relevant to the stack overflow answer
> you
> > mentioned?
> >
> > commit ab036bdedbb49ecc96d550b5e883e43bb03eaccc
> > Author: João Távora <joaotavora <at> gmail.com>
> > Date:   Fri Dec 21 18:00:08 2018 +0000
> >
> >     Extend electric-layout-mode to handle more complex layouts
> >
> >     Also, have it play nice with electric-pair-mode.
> >
> >     Multiple matching entries in `electric-layout-rules' are executed in
> >     order of appearance.  When inserting a newline in the 'after-stay
> >     rule, ensure electric-pair-open-newline-between-pairs is nil.
> >
> >     Arguably the logic behind electric-pair-open-newline-between-pairs
> >     should be moved to electric-layout-mode, but the current
> rule-matching
> >     engine doesn't allow for it.  The current solution seems to be good
> >     enough for the situations reported in bug#33794.
> >
> >     * lisp/electric.el (electric-layout-rules): Adjust docstring.
> >     (electric-layout-post-self-insert-function): Loop through rules.
> Bind
> >     electric-pair-open-newline-between-pairs to nil when handling
> >     after-stay.
> >
> > diff --git a/lisp/electric.el b/lisp/electric.el
> > index 6dbf46b80c..6a307a49b9 100644
> > --- a/lisp/electric.el
> > +++ b/lisp/electric.el
> > @@ -370,38 +370,43 @@ electric-layout-rules
> >
> >  The symbols specify where in relation to CHAR the newline
> >  character(s) should be inserted. `after-stay' means insert a
> > -newline after CHAR but stay in the same place.")
> > +newline after CHAR but stay in the same place.
> > +
> > +If multiple rules match, they are all executed in order of
> > +appearance.")
> >
> >  (defun electric-layout-post-self-insert-function ()
> > -  (let* ((rule (cdr (assq last-command-event electric-layout-rules)))
> > -         pos)
> > -    (when (and rule
> > -               (setq pos (electric--after-char-pos))
> > +  (let (pos)
> > +    (when (and (setq pos (electric--after-char-pos))
> >                 ;; Not in a string or comment.
> >                 (not (nth 8 (save-excursion (syntax-ppss pos)))))
> > -      (let ((end (point-marker))
> > -            (sym (if (functionp rule) (funcall rule) rule)))
> > -        (set-marker-insertion-type end (not (eq sym 'after-stay)))
> > -        (goto-char pos)
> > -        (pcase sym
> > -          ;; FIXME: we used `newline' down here which called
> > -          ;; self-insert-command and ran post-self-insert-hook
> recursively.
> > -          ;; It happened to make electric-indent-mode work
> automatically with
> > -          ;; electric-layout-mode (at the cost of re-indenting lines
> > -          ;; multiple times), but I'm not sure it's what we want.
> > -          ;;
> > -          ;; FIXME: check eolp before inserting \n?
> > -          ('before (goto-char (1- pos)) (skip-chars-backward " \t")
> > -                   (unless (bolp) (insert "\n")))
> > -          ('after  (insert "\n"))
> > -          ('after-stay (save-excursion
> > -                         (let ((electric-layout-rules nil))
> > -                           (newline 1 t))))
> > -          ('around (save-excursion
> > -                     (goto-char (1- pos)) (skip-chars-backward " \t")
> > -                     (unless (bolp) (insert "\n")))
> > -                   (insert "\n")))      ; FIXME: check eolp before
> inserting \n?
> > -        (goto-char end)))))
> > +      (goto-char pos)
> > +      (dolist (rule electric-layout-rules)
> > +        (when (eq last-command-event (car rule))
> > +          (let* ((end (point-marker))
> > +                 (rule (cdr rule))
> > +                 (sym (if (functionp rule) (funcall rule) rule)))
> > +            (set-marker-insertion-type end (not (eq sym 'after-stay)))
> > +            (pcase sym
> > +              ;; FIXME: we used `newline' down here which called
> > +              ;; self-insert-command and ran post-self-insert-hook
> recursively.
> > +              ;; It happened to make electric-indent-mode work
> automatically with
> > +              ;; electric-layout-mode (at the cost of re-indenting lines
> > +              ;; multiple times), but I'm not sure it's what we want.
> > +              ;;
> > +              ;; FIXME: check eolp before inserting \n?
> > +              ('before (goto-char (1- pos)) (skip-chars-backward " \t")
> > +                       (unless (bolp) (insert "\n")))
> > +              ('after  (insert "\n"))
> > +              ('after-stay (save-excursion
> > +                             (let ((electric-layout-rules nil)
> > +
>  (electric-pair-open-newline-between-pairs nil))
> > +                               (newline 1 t))))
> > +              ('around (save-excursion
> > +                         (goto-char (1- pos)) (skip-chars-backward "
> \t")
> > +                         (unless (bolp) (insert "\n")))
> > +                       (insert "\n")))      ; FIXME: check eolp before
> inserting \n?
> > +            (goto-char end)))))))
> >
> >  (put 'electric-layout-post-self-insert-function 'priority  40)
> >
>
[Message part 2 (text/html, inline)]

Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Fri, 21 Dec 2018 19:25:02 GMT) Full text and rfc822 format available.

Message #29 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: João Távora <joaotavora <at> gmail.com>
To: bea <at> klebe.blog
Cc: Alan Mackenzie <acm <at> muc.de>, Stefan Monnier <monnier <at> iro.umontreal.ca>,
 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Fri, 21 Dec 2018 19:24:02 +0000
[Message part 1 (text/plain, inline)]
By the way, Stefan, this patch is only an idea, and maybe not a very good
one since it may break backward compatibility in electric-layout-rules.
After having seen Beatrix's link to your so answer, I see that two separate
rules on two separate chars should also work for this.

João

On Fri, Dec 21, 2018, 19:20 João Távora <joaotavora <at> gmail.com wrote:

> Hi Beatrix,
>
> The solution I propose involves introducing the hotpatch I attached to fix
> electric-layout-mode in your emacs, so I wouldn't expect it to work if you
> haven't done that.
>
> Do you know how to do it?
>
> Though Alan will probably suggest otherwise, I'd also steer away from
> c-specific functionality and keep to the triad electric-indent-mode,
> electric-pair-mode and electric-indent-mode, at least while we try to
> extend/fix these modes to accommodate your needs.
>
> After such a solution is evaluated, you can select to keep it or move to
> something else.
>
> João
>
> On Fri, Dec 21, 2018, 19:06 Beatrix Klebe <beeuhtricks <at> gmail.com wrote:
>
>> Here's the link, I believe it was Stefan that answered it:
>>
>> https://emacs.stackexchange.com/questions/2837/automatically-formatting-brackets/2853#2853
>>
>> I have tried this with emacs -Q and it does not fix the issue, which
>> is as follows.
>>
>> Ordinarily in cc-mode when you have auto-newline-mode activated, and
>> as far as I can tell, a cc-mode configuration that supports it, (which
>> csharp-mode contains), the following happens when opening a block
>> (pipe is the cursor):
>>
>> void Main() {| // opening bracket is typed
>>
>> becomes
>>
>> void Main
>> {
>>     |
>>
>> when c-toggle-auto-newline is activated. However, if you also want
>> your braces automatically paired, with electric-pair-mode, instead the
>> following occurs:
>>
>> void Main() {| // opening bracket is typed
>>
>> void Main() {|} // electric-pair-mode closes the open bracket, but
>> auto-newline-mode does not appear to do anything.
>>
>> void Main() {
>>     |
>> } // user hits return, inserting the cursor at the correct indent
>> level, but leaving the opening brace where it is.
>>
>> The ideal/desired behavior is:
>>
>> void Main() {| // opening bracket is typed
>>
>> void Main()
>> {
>>     |
>> } // user hits return key, electric-pair-mode pairs up the brackets,
>> and auto-newline-mode formats the braces correctly
>>
>> It would also probably suffice to format with the newline before
>> hitting enter as well, although I think I prefer hitting enter to open
>> the block. I'm quite curious as to the internals of these formatting
>> systems and would be happy to help with a fix/feature if that would be
>> desired, I am mostly an OCaml programmer but C# is my day job and I've
>> just recently gotten deeper into Emacs Lisp.
>>
>> On Fri, Dec 21, 2018 at 1:49 PM João Távora <joaotavora <at> gmail.com> wrote:
>> >
>> > Beatrix Klebe <beeuhtricks <at> gmail.com> writes:
>> >
>> > > I believe I saw your Stack Overflow answer about this while searching
>> > > for the solution. electric-layout-mode works with some quirks, such as
>> > > that if you put a space after parens in a function definition, the
>> > > space gets carried on to the newline with that method, which is a bit
>> > > annoying. What would be ideal, and what I'm looking for, is to get
>> > > auto-pairing of brackets with braces being placed where they should be
>> > > automatically and the insertion point getting put in between them at
>> > > the correct indent level, such as what happens with Visual Studio, or
>> > > Visual Studio Code, or several other editors with this functionality.
>> > > Perhaps it is not emacslike to have such behavior be totally
>> > > automated, but I am used to it and finds it decreases my ordinary
>> > > levels of frustration when working with verbose and imperative
>> > > languages. I am currently trying to write some insert specifiers for
>> > > smartparens to do this, but it is proving more difficult to find an
>> > > elegant solution than I had expected.
>> >
>> > It is quite emacslike (though maybe not activated by default): you just
>> > have to report the bugs to the Emacs developers as efficiently as
>> > possible.
>> >
>> > 1. Though Alan possibly has already, I still cannot understand the
>> >    original problem.  Can you start by describing what the buffer looked
>> >    like before, what you did, what it looked like afterwards, and what
>> >    you expected it to look like?  If possible start with a clean Emacs
>> >    -Q recpe.
>> >
>> > 2. I have experimented with nicer-playing like alternatives like
>> >    electric-layout-mode.  I came across a few quirks myself (though I'm
>> >    not sure if they are the same as yours). So I prepared a patch (in
>> >    branch scratch/fix-33794-extend-electric-layout-mode) and attached
>> >    it after the sig.
>> >
>> > After loading this patch, in a simple Emacs -Q the configuration:
>> >
>> >    (electric-pair-mode)
>> >    (electric-layout-mode)
>> >
>> >    (add-hook 'c-mode-hook
>> >           (lambda ()
>> >             (setq-local electric-layout-rules
>> >                         '((?\{ . after)
>> >                           (?\{ . after-stay)))))
>> >
>> > And, when visiting a C file, if I press `{' I get the expected
>> > pair+layout+indent behaviour.  Sor example opening a brace after
>> > int main () gives me:
>> >
>> >     int main () {
>> >         <cursor here>
>> >     }
>> >
>> > I, like Stefan, think cc-mode could/should set electric-layout-rules
>> > buffer-locally to reflect whatever c-style the user has selected.
>> >
>> > Thanks,
>> > João
>> >
>> > PS: Also, can you link to the the relevant to the stack overflow answer
>> you
>> > mentioned?
>> >
>> > commit ab036bdedbb49ecc96d550b5e883e43bb03eaccc
>> > Author: João Távora <joaotavora <at> gmail.com>
>> > Date:   Fri Dec 21 18:00:08 2018 +0000
>> >
>> >     Extend electric-layout-mode to handle more complex layouts
>> >
>> >     Also, have it play nice with electric-pair-mode.
>> >
>> >     Multiple matching entries in `electric-layout-rules' are executed in
>> >     order of appearance.  When inserting a newline in the 'after-stay
>> >     rule, ensure electric-pair-open-newline-between-pairs is nil.
>> >
>> >     Arguably the logic behind electric-pair-open-newline-between-pairs
>> >     should be moved to electric-layout-mode, but the current
>> rule-matching
>> >     engine doesn't allow for it.  The current solution seems to be good
>> >     enough for the situations reported in bug#33794.
>> >
>> >     * lisp/electric.el (electric-layout-rules): Adjust docstring.
>> >     (electric-layout-post-self-insert-function): Loop through rules.
>> Bind
>> >     electric-pair-open-newline-between-pairs to nil when handling
>> >     after-stay.
>> >
>> > diff --git a/lisp/electric.el b/lisp/electric.el
>> > index 6dbf46b80c..6a307a49b9 100644
>> > --- a/lisp/electric.el
>> > +++ b/lisp/electric.el
>> > @@ -370,38 +370,43 @@ electric-layout-rules
>> >
>> >  The symbols specify where in relation to CHAR the newline
>> >  character(s) should be inserted. `after-stay' means insert a
>> > -newline after CHAR but stay in the same place.")
>> > +newline after CHAR but stay in the same place.
>> > +
>> > +If multiple rules match, they are all executed in order of
>> > +appearance.")
>> >
>> >  (defun electric-layout-post-self-insert-function ()
>> > -  (let* ((rule (cdr (assq last-command-event electric-layout-rules)))
>> > -         pos)
>> > -    (when (and rule
>> > -               (setq pos (electric--after-char-pos))
>> > +  (let (pos)
>> > +    (when (and (setq pos (electric--after-char-pos))
>> >                 ;; Not in a string or comment.
>> >                 (not (nth 8 (save-excursion (syntax-ppss pos)))))
>> > -      (let ((end (point-marker))
>> > -            (sym (if (functionp rule) (funcall rule) rule)))
>> > -        (set-marker-insertion-type end (not (eq sym 'after-stay)))
>> > -        (goto-char pos)
>> > -        (pcase sym
>> > -          ;; FIXME: we used `newline' down here which called
>> > -          ;; self-insert-command and ran post-self-insert-hook
>> recursively.
>> > -          ;; It happened to make electric-indent-mode work
>> automatically with
>> > -          ;; electric-layout-mode (at the cost of re-indenting lines
>> > -          ;; multiple times), but I'm not sure it's what we want.
>> > -          ;;
>> > -          ;; FIXME: check eolp before inserting \n?
>> > -          ('before (goto-char (1- pos)) (skip-chars-backward " \t")
>> > -                   (unless (bolp) (insert "\n")))
>> > -          ('after  (insert "\n"))
>> > -          ('after-stay (save-excursion
>> > -                         (let ((electric-layout-rules nil))
>> > -                           (newline 1 t))))
>> > -          ('around (save-excursion
>> > -                     (goto-char (1- pos)) (skip-chars-backward " \t")
>> > -                     (unless (bolp) (insert "\n")))
>> > -                   (insert "\n")))      ; FIXME: check eolp before
>> inserting \n?
>> > -        (goto-char end)))))
>> > +      (goto-char pos)
>> > +      (dolist (rule electric-layout-rules)
>> > +        (when (eq last-command-event (car rule))
>> > +          (let* ((end (point-marker))
>> > +                 (rule (cdr rule))
>> > +                 (sym (if (functionp rule) (funcall rule) rule)))
>> > +            (set-marker-insertion-type end (not (eq sym 'after-stay)))
>> > +            (pcase sym
>> > +              ;; FIXME: we used `newline' down here which called
>> > +              ;; self-insert-command and ran post-self-insert-hook
>> recursively.
>> > +              ;; It happened to make electric-indent-mode work
>> automatically with
>> > +              ;; electric-layout-mode (at the cost of re-indenting
>> lines
>> > +              ;; multiple times), but I'm not sure it's what we want.
>> > +              ;;
>> > +              ;; FIXME: check eolp before inserting \n?
>> > +              ('before (goto-char (1- pos)) (skip-chars-backward " \t")
>> > +                       (unless (bolp) (insert "\n")))
>> > +              ('after  (insert "\n"))
>> > +              ('after-stay (save-excursion
>> > +                             (let ((electric-layout-rules nil)
>> > +
>>  (electric-pair-open-newline-between-pairs nil))
>> > +                               (newline 1 t))))
>> > +              ('around (save-excursion
>> > +                         (goto-char (1- pos)) (skip-chars-backward "
>> \t")
>> > +                         (unless (bolp) (insert "\n")))
>> > +                       (insert "\n")))      ; FIXME: check eolp before
>> inserting \n?
>> > +            (goto-char end)))))))
>> >
>> >  (put 'electric-layout-post-self-insert-function 'priority  40)
>> >
>>
>
[Message part 2 (text/html, inline)]

Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Fri, 21 Dec 2018 19:44:02 GMT) Full text and rfc822 format available.

Message #32 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Beatrix Klebe <beeuhtricks <at> gmail.com>
To: João Távora <joaotavora <at> gmail.com>
Cc: Alan Mackenzie <acm <at> muc.de>, "Mx. Beatrix Klebe" <bea <at> klebe.blog>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>, 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Fri, 21 Dec 2018 14:43:41 -0500
I know how to do hotpaches but that doesn't appear to solve the
problem I'm having here, unless I've missed something. The problem is
with moving the opening bracket, not the insertion point.


On Fri, Dec 21, 2018 at 2:20 PM João Távora <joaotavora <at> gmail.com> wrote:
>
> Hi Beatrix,
>
> The solution I propose involves introducing the hotpatch I attached to fix electric-layout-mode in your emacs, so I wouldn't expect it to work if you haven't done that.
>
> Do you know how to do it?
>
> Though Alan will probably suggest otherwise, I'd also steer away from c-specific functionality and keep to the triad electric-indent-mode, electric-pair-mode and electric-indent-mode, at least while we try to extend/fix these modes to accommodate your needs.
>
> After such a solution is evaluated, you can select to keep it or move to something else.
>
> João
>
> On Fri, Dec 21, 2018, 19:06 Beatrix Klebe <beeuhtricks <at> gmail.com wrote:
>>
>> Here's the link, I believe it was Stefan that answered it:
>> https://emacs.stackexchange.com/questions/2837/automatically-formatting-brackets/2853#2853
>>
>> I have tried this with emacs -Q and it does not fix the issue, which
>> is as follows.
>>
>> Ordinarily in cc-mode when you have auto-newline-mode activated, and
>> as far as I can tell, a cc-mode configuration that supports it, (which
>> csharp-mode contains), the following happens when opening a block
>> (pipe is the cursor):
>>
>> void Main() {| // opening bracket is typed
>>
>> becomes
>>
>> void Main
>> {
>>     |
>>
>> when c-toggle-auto-newline is activated. However, if you also want
>> your braces automatically paired, with electric-pair-mode, instead the
>> following occurs:
>>
>> void Main() {| // opening bracket is typed
>>
>> void Main() {|} // electric-pair-mode closes the open bracket, but
>> auto-newline-mode does not appear to do anything.
>>
>> void Main() {
>>     |
>> } // user hits return, inserting the cursor at the correct indent
>> level, but leaving the opening brace where it is.
>>
>> The ideal/desired behavior is:
>>
>> void Main() {| // opening bracket is typed
>>
>> void Main()
>> {
>>     |
>> } // user hits return key, electric-pair-mode pairs up the brackets,
>> and auto-newline-mode formats the braces correctly
>>
>> It would also probably suffice to format with the newline before
>> hitting enter as well, although I think I prefer hitting enter to open
>> the block. I'm quite curious as to the internals of these formatting
>> systems and would be happy to help with a fix/feature if that would be
>> desired, I am mostly an OCaml programmer but C# is my day job and I've
>> just recently gotten deeper into Emacs Lisp.
>>
>> On Fri, Dec 21, 2018 at 1:49 PM João Távora <joaotavora <at> gmail.com> wrote:
>> >
>> > Beatrix Klebe <beeuhtricks <at> gmail.com> writes:
>> >
>> > > I believe I saw your Stack Overflow answer about this while searching
>> > > for the solution. electric-layout-mode works with some quirks, such as
>> > > that if you put a space after parens in a function definition, the
>> > > space gets carried on to the newline with that method, which is a bit
>> > > annoying. What would be ideal, and what I'm looking for, is to get
>> > > auto-pairing of brackets with braces being placed where they should be
>> > > automatically and the insertion point getting put in between them at
>> > > the correct indent level, such as what happens with Visual Studio, or
>> > > Visual Studio Code, or several other editors with this functionality.
>> > > Perhaps it is not emacslike to have such behavior be totally
>> > > automated, but I am used to it and finds it decreases my ordinary
>> > > levels of frustration when working with verbose and imperative
>> > > languages. I am currently trying to write some insert specifiers for
>> > > smartparens to do this, but it is proving more difficult to find an
>> > > elegant solution than I had expected.
>> >
>> > It is quite emacslike (though maybe not activated by default): you just
>> > have to report the bugs to the Emacs developers as efficiently as
>> > possible.
>> >
>> > 1. Though Alan possibly has already, I still cannot understand the
>> >    original problem.  Can you start by describing what the buffer looked
>> >    like before, what you did, what it looked like afterwards, and what
>> >    you expected it to look like?  If possible start with a clean Emacs
>> >    -Q recpe.
>> >
>> > 2. I have experimented with nicer-playing like alternatives like
>> >    electric-layout-mode.  I came across a few quirks myself (though I'm
>> >    not sure if they are the same as yours). So I prepared a patch (in
>> >    branch scratch/fix-33794-extend-electric-layout-mode) and attached
>> >    it after the sig.
>> >
>> > After loading this patch, in a simple Emacs -Q the configuration:
>> >
>> >    (electric-pair-mode)
>> >    (electric-layout-mode)
>> >
>> >    (add-hook 'c-mode-hook
>> >           (lambda ()
>> >             (setq-local electric-layout-rules
>> >                         '((?\{ . after)
>> >                           (?\{ . after-stay)))))
>> >
>> > And, when visiting a C file, if I press `{' I get the expected
>> > pair+layout+indent behaviour.  Sor example opening a brace after
>> > int main () gives me:
>> >
>> >     int main () {
>> >         <cursor here>
>> >     }
>> >
>> > I, like Stefan, think cc-mode could/should set electric-layout-rules
>> > buffer-locally to reflect whatever c-style the user has selected.
>> >
>> > Thanks,
>> > João
>> >
>> > PS: Also, can you link to the the relevant to the stack overflow answer you
>> > mentioned?
>> >
>> > commit ab036bdedbb49ecc96d550b5e883e43bb03eaccc
>> > Author: João Távora <joaotavora <at> gmail.com>
>> > Date:   Fri Dec 21 18:00:08 2018 +0000
>> >
>> >     Extend electric-layout-mode to handle more complex layouts
>> >
>> >     Also, have it play nice with electric-pair-mode.
>> >
>> >     Multiple matching entries in `electric-layout-rules' are executed in
>> >     order of appearance.  When inserting a newline in the 'after-stay
>> >     rule, ensure electric-pair-open-newline-between-pairs is nil.
>> >
>> >     Arguably the logic behind electric-pair-open-newline-between-pairs
>> >     should be moved to electric-layout-mode, but the current rule-matching
>> >     engine doesn't allow for it.  The current solution seems to be good
>> >     enough for the situations reported in bug#33794.
>> >
>> >     * lisp/electric.el (electric-layout-rules): Adjust docstring.
>> >     (electric-layout-post-self-insert-function): Loop through rules.  Bind
>> >     electric-pair-open-newline-between-pairs to nil when handling
>> >     after-stay.
>> >
>> > diff --git a/lisp/electric.el b/lisp/electric.el
>> > index 6dbf46b80c..6a307a49b9 100644
>> > --- a/lisp/electric.el
>> > +++ b/lisp/electric.el
>> > @@ -370,38 +370,43 @@ electric-layout-rules
>> >
>> >  The symbols specify where in relation to CHAR the newline
>> >  character(s) should be inserted. `after-stay' means insert a
>> > -newline after CHAR but stay in the same place.")
>> > +newline after CHAR but stay in the same place.
>> > +
>> > +If multiple rules match, they are all executed in order of
>> > +appearance.")
>> >
>> >  (defun electric-layout-post-self-insert-function ()
>> > -  (let* ((rule (cdr (assq last-command-event electric-layout-rules)))
>> > -         pos)
>> > -    (when (and rule
>> > -               (setq pos (electric--after-char-pos))
>> > +  (let (pos)
>> > +    (when (and (setq pos (electric--after-char-pos))
>> >                 ;; Not in a string or comment.
>> >                 (not (nth 8 (save-excursion (syntax-ppss pos)))))
>> > -      (let ((end (point-marker))
>> > -            (sym (if (functionp rule) (funcall rule) rule)))
>> > -        (set-marker-insertion-type end (not (eq sym 'after-stay)))
>> > -        (goto-char pos)
>> > -        (pcase sym
>> > -          ;; FIXME: we used `newline' down here which called
>> > -          ;; self-insert-command and ran post-self-insert-hook recursively.
>> > -          ;; It happened to make electric-indent-mode work automatically with
>> > -          ;; electric-layout-mode (at the cost of re-indenting lines
>> > -          ;; multiple times), but I'm not sure it's what we want.
>> > -          ;;
>> > -          ;; FIXME: check eolp before inserting \n?
>> > -          ('before (goto-char (1- pos)) (skip-chars-backward " \t")
>> > -                   (unless (bolp) (insert "\n")))
>> > -          ('after  (insert "\n"))
>> > -          ('after-stay (save-excursion
>> > -                         (let ((electric-layout-rules nil))
>> > -                           (newline 1 t))))
>> > -          ('around (save-excursion
>> > -                     (goto-char (1- pos)) (skip-chars-backward " \t")
>> > -                     (unless (bolp) (insert "\n")))
>> > -                   (insert "\n")))      ; FIXME: check eolp before inserting \n?
>> > -        (goto-char end)))))
>> > +      (goto-char pos)
>> > +      (dolist (rule electric-layout-rules)
>> > +        (when (eq last-command-event (car rule))
>> > +          (let* ((end (point-marker))
>> > +                 (rule (cdr rule))
>> > +                 (sym (if (functionp rule) (funcall rule) rule)))
>> > +            (set-marker-insertion-type end (not (eq sym 'after-stay)))
>> > +            (pcase sym
>> > +              ;; FIXME: we used `newline' down here which called
>> > +              ;; self-insert-command and ran post-self-insert-hook recursively.
>> > +              ;; It happened to make electric-indent-mode work automatically with
>> > +              ;; electric-layout-mode (at the cost of re-indenting lines
>> > +              ;; multiple times), but I'm not sure it's what we want.
>> > +              ;;
>> > +              ;; FIXME: check eolp before inserting \n?
>> > +              ('before (goto-char (1- pos)) (skip-chars-backward " \t")
>> > +                       (unless (bolp) (insert "\n")))
>> > +              ('after  (insert "\n"))
>> > +              ('after-stay (save-excursion
>> > +                             (let ((electric-layout-rules nil)
>> > +                                   (electric-pair-open-newline-between-pairs nil))
>> > +                               (newline 1 t))))
>> > +              ('around (save-excursion
>> > +                         (goto-char (1- pos)) (skip-chars-backward " \t")
>> > +                         (unless (bolp) (insert "\n")))
>> > +                       (insert "\n")))      ; FIXME: check eolp before inserting \n?
>> > +            (goto-char end)))))))
>> >
>> >  (put 'electric-layout-post-self-insert-function 'priority  40)
>> >




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Fri, 21 Dec 2018 20:18:02 GMT) Full text and rfc822 format available.

Message #35 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: Stefan Monnier <monnier <at> IRO.UMontreal.CA>
Cc: bea <at> klebe.blog, João Távora <joaotavora <at> gmail.com>,
 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Fri, 21 Dec 2018 20:11:06 +0000
Hello, Stefan.

On Fri, Dec 21, 2018 at 09:12:49 -0500, Stefan Monnier wrote:
> >> Yes.  What is happening, from the viewpoint of CC Mode, is that on
> >> inserting a {, electric-pair-mode is prematurely inserting its }, before
> >> the processing for the { is complete.

> Since it's done from post-self-insert-hook, it's done at the very end of
> inserting { so I'm not sure what you mean by "before the processing for
> the { is complete".

c-electric-brace calls self-insert-function then performs the rest of
its processing.

> >> Also, due to the way } gets inserted, the CC Mode processing for
> >> the } isn't done at all.

> I think you meant "due to the way CC-Mode hooks itself into the }
> processing, ..." ;-)

No, not at all.  CC Mode has been working for several decades, and works
well.  electric-pair-mode is the new kid on the block, just a few years
old, and was apparently hacked together without regard to some well
established conventions.  It should have provided interfaces to allow
existing software to connect to it - for example a variable to contain a
function to insert the electric character, or something like that.
Maybe.  It should have been considered, but apparently wasn't.

> >> Would it therefore be possible, rather than having a crude insertion on
> >> post-self-insert-hook, to use something like post-command-hook to allow
> >> the insertion of the { first to complete?  Then, rather than using the
> >> brutal self-insert-command for } in electric-pair--insert, use the
> >> command to which the key } is bound?

> Talking about brutal: how could electric-pair-mode run whichever command
> is bound to } without taking the risk of running a much more brutal
> command than one that inserts a character?

That isn't a risk.  It's a user decision.

> > FWIW, I think cc-mode should rather use post-self-insert-hook instead
> > of redefining ....

There's no "redefining".  There's definition of functions bound to keys,
and these definitions are several decades old and work well.  Such
software construction is recommended by the Emacs manual (page "Major
Modes").

> > .... commands for keys whose expected behaviour is (with minor
> > variations presumably covered by abundant hookage) self-insertion.

post-self-insert-hook smells bad.  I can't quite put my finger on what's
wrong with it, but it definitely doesn't feel good.  Anyhow, it's too
new for CC Mode.  And it would involve a lot of work for no increase in
functionality.

The fault lies in electric-pair-mode's failure to provide appropriate
interfaces for existing code to use it.

> IIRC it should be able to just use electric-layout-mode for that (tho
> maybe electric-layout's featureset doesn't currently cover 100% that of
> CC-mode's auto-newline, in which case it would be nice to extend
> electric-layout accordingly).

electric-layout-mode seems to be a reinvention of the wheel,
incomptible, sadly, with the original in CC Mode.  That original works
well.  The copy likely works less well, though I admit not having
examined it in any great detail.

> For things like electric-pair, electric-indent, and electric-layout to
> work correctly together, they need to agree on some convention.

Yes.  I've searched the emacs-devel archives briefly, and found no
attempt there to sketch out and discuss such a convention, and
definitely no attempt to reach any agreement.  Maybe I've missed
something, but given how recent these electric-.. things are (2010),
it's likely I would have been involved in such discussion had it taken
place, and it's likely electric-pair-mode wouldn't now be clashing with
CC Mode.

> Note that CC-mode can also side-step that convention and use `insert`
> instead of self-insert-command.

That wouldn't help electric-pair-mode work in CC Mode, I think.

>         Stefan

-- 
Alan Mackenzie (Nuremberg, Germany).




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Fri, 21 Dec 2018 21:58:01 GMT) Full text and rfc822 format available.

Message #38 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: João Távora <joaotavora <at> gmail.com>
Cc: bea <at> klebe.blog, 33794 <at> debbugs.gnu.org,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Fri, 21 Dec 2018 21:50:42 +0000
Hello, João.

On Fri, Dec 21, 2018 at 13:57:21 +0000, João Távora wrote:
> On Fri, Dec 21, 2018 at 1:48 PM Alan Mackenzie <acm <at> muc.de> wrote:

> > Hello, Beatrix.

> > In article <mailman.5894.1545155289.1284.bug-gnu-emacs <at> gnu.org> you wrote:
> > > When using cc-mode, turning on electric-pair-mode causes the
> > > auto-newline minor mode to stop inserting newlines where expected. This
> > > is relevant to the formatting of C# code with the Allman/BSD brace style
> > > in particular, though it would be nice if these modes specifically did
> > > work together.

> > Yes.  What is happening, from the viewpoint of CC Mode, is that on
> > inserting a {, electric-pair-mode is prematurely inserting its }, before
> > the processing for the { is complete.  Also, due to the way } gets
> > inserted, the CC Mode processing for the } isn't done at all.

> > @João: I think electric pair mode is intended to simulate the manual
> > insertion of a matching paren, etc., when a paren, etc., is typed.

> > Would it therefore be possible, rather than having a crude insertion on
> > post-self-insert-hook, to use something like post-command-hook to allow
> > the insertion of the { first to complete?  Then, rather than using the
> > brutal self-insert-command for } in electric-pair--insert, use the
> > command to which the key } is bound?  This should allow CC Mode's
> > auto-newline facility to work, and also more closely simulate the manual
> > insertion of the closing delimiter.


> I don't know.  We better ask Stefan (CC'ed) who I believe designed the
> original strategy of inserting closing delimiters in the previous
> electric-pair-mode. That didn't change in my redesign.

> FWIW, I think cc-mode should rather use post-self-insert-hook instead
> of redefining commands for keys whose expected behaviour is
> (with minor variations presumably covered by abundant hookage)
> self-insertion.  If you place your specific cc-mode processing late
> enough in the hook then its insertion will be "complete" for all
> practical purposes.

I think I've worked out what I don't like about such (ab)use of
post-self-insert-hook.  There are 113 uses of self-insert-command in our
sources, and it seems most of them expect self-insert-command to do just
that, with possible things like refilling.  If one makes additional
buffer changes, one will foul up many of these 113 uses of s-i-c.

It is a bit like before/after-change-functions.  Although it is not
written in tablets of stone anywhere (as fas as I'm aware), there's an
understanding that you don't make buffer changes inside b/a-c-f.  The
same should apply to post-self-insert-hook, which is a sort of change
hook, for the same reasons.

> João

-- 
Alan Mackenzie (Nuremberg, Germany).




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sat, 22 Dec 2018 00:46:02 GMT) Full text and rfc822 format available.

Message #41 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: João Távora <joaotavora <at> gmail.com>
To: Alan Mackenzie <acm <at> muc.de>
Cc: bea <at> klebe.blog, Stefan Monnier <monnier <at> IRO.UMontreal.CA>,
 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1;
 electric-pair-mode breaks auto-newline minor mode of cc-mode
Date: Sat, 22 Dec 2018 00:45:20 +0000
Hi Alan,

I will be replying to the two emails you sent me in this single message.

Alan Mackenzie <acm <at> muc.de> writes:

> No, not at all.  CC Mode has been working for several decades, and works
> well.  electric-pair-mode is the new kid on the block, just a few years
> old, and was apparently hacked together without regard to some well
> established conventions.  It should have provided interfaces to allow
> existing software to connect to it - for example a variable to contain a
> function to insert the electric character, or something like that.
> Maybe.  It should have been considered, but apparently wasn't.

First, I think you'll agree that antiquity is a poor measure of the
merits of software.  Here's a characteristic of electric-pair-mode that
I think is an actual merit: it works for every mode in Emacs..

Also, I don't know if you understand the history of electric-pair-mode.
It has two generations: One, before 24.4, which I believe Stefan wrote,
where it was a simpler mode to automatically insert parenthesis and
quotes as described in electric-pair-pairs.  Then, in 24.4, I borrowed
code from my reasonably popular autopair.el extension and e-p-m became a
mode that automatically infers what characters to pair from the syntax
table of each mode.  Furthermore, in the new version, it also makes
educated guesses about when to pair or when not to pair based, again on
the information collected from the buffer and its syntax table by
syntax-ppss.

The use of post-self-insert-hook was a requirement at the time, since
that is how the pre-24.4 electric-pair-mode, electric-indent-mode and
electric-layout-mode already worked.  I welcomed this requirement, and
it was what encouraged me to kill autopair.el and migrate to the new
framework, since in autopair.el I had to rebind the parenthesis keys,
which is akward (much like c-electric-brace and c-electric-paren are
akward IMO).  This simplified the code tremendously.

So these "well established conventions" are, with all due respect,
nothing more than personal opinions based on a narrow experience with a
subset of modes (maybe "mode" singular), tried and tested as it may be.

If I abandon the post-self-insert-hook convention for e-p-m, I'll
probably be breaking the e-p-m interaction with electric-indent-mode,
electric-layout-mode, etc.  If there are existing problems with these
interactions they should be fixed, but I will not fix e-p-m for
interaction a specific part of cc-mode, unless you provide
retro-compatible fix that guarantees existing behaviour outside cc-mode.

I would rather declare e-p-m incompatible with that part of cc-mode and
invest some time in providing alternatives based on
electric-layout-mode, fixing Beatrix's problem by replacing bits of
cc-mode-specific initialization in her init file with bits that works
for all modes, including cc-mode.

João








Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sat, 22 Dec 2018 01:10:02 GMT) Full text and rfc822 format available.

Message #44 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: João Távora <joaotavora <at> gmail.com>
To: Beatrix Klebe <beeuhtricks <at> gmail.com>
Cc: Alan Mackenzie <acm <at> muc.de>, bea <at> klebe.blog,
 Stefan Monnier <monnier <at> iro.umontreal.ca>, 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1;
 electric-pair-mode breaks auto-newline minor mode of cc-mode
Date: Sat, 22 Dec 2018 01:08:54 +0000
Beatrix Klebe <beeuhtricks <at> gmail.com> writes:

> I know how to do hotpaches but that doesn't appear to solve the
> problem I'm having here, unless I've missed something. The problem is
> with moving the opening bracket, not the insertion point.

Beatrix,

I think you may have missed the fact that I am suggesting alternatives
that:

* involve cc-mode, or one of its derived modes;

* don't involve M-x c-toggle-auto-newline (turning on what you call
  auto-newline-mode);

* involve turning on the global electric-layout-mode and a thin
  customization for it in the buffers where you think it's relevant
  (presumably cc-mode);

* may involve multiple fixed/patched versions of lisp/electric.el as I
  understand your problem(s);

As it stands, the last patch I sent you passes my only test which is
this:  given a file 33794.el which is just:

   (electric-pair-mode)
   (electric-layout-mode)
    
   (add-hook 'c-mode-hook
             (lambda ()
               (setq-local electric-layout-rules
                           '((?\{ . after)
                             (?\{ . after-stay)))))


then running this from a shell:

   $ emacs -Q -l 33794.el something.c

Opens a new c-mode buffer.  Type 'int main ()' and then an opening
brace.  You should get:

   int main () {
       <cursor>
   }

Can you reproduce these results?  If you can come up with more of these
tests written in this or a similarly simple and exact manner it's easier
for me to understand what's going on (it's also easier to write
automated tests).

João

>
>
> On Fri, Dec 21, 2018 at 2:20 PM João Távora <joaotavora <at> gmail.com> wrote:
>>
>> Hi Beatrix,
>>
>> The solution I propose involves introducing the hotpatch I attached
>> to fix electric-layout-mode in your emacs, so I wouldn't expect it
>> to work if you haven't done that.
>>
>> Do you know how to do it?
>>
>> Though Alan will probably suggest otherwise, I'd also steer away
>> from c-specific functionality and keep to the triad
>> electric-indent-mode, electric-pair-mode and electric-indent-mode,
>> at least while we try to extend/fix these modes to accommodate your
>> needs.
>>
>> After such a solution is evaluated, you can select to keep it or move to something else.
>>
>> João
>>
>> On Fri, Dec 21, 2018, 19:06 Beatrix Klebe <beeuhtricks <at> gmail.com wrote:
>>>
>>> Here's the link, I believe it was Stefan that answered it:
>>> https://emacs.stackexchange.com/questions/2837/automatically-formatting-brackets/2853#2853
>>>
>>> I have tried this with emacs -Q and it does not fix the issue, which
>>> is as follows.
>>>
>>> Ordinarily in cc-mode when you have auto-newline-mode activated, and
>>> as far as I can tell, a cc-mode configuration that supports it, (which
>>> csharp-mode contains), the following happens when opening a block
>>> (pipe is the cursor):
>>>
>>> void Main() {| // opening bracket is typed
>>>
>>> becomes
>>>
>>> void Main
>>> {
>>>     |
>>>
>>> when c-toggle-auto-newline is activated. However, if you also want
>>> your braces automatically paired, with electric-pair-mode, instead the
>>> following occurs:
>>>
>>> void Main() {| // opening bracket is typed
>>>
>>> void Main() {|} // electric-pair-mode closes the open bracket, but
>>> auto-newline-mode does not appear to do anything.
>>>
>>> void Main() {
>>>     |
>>> } // user hits return, inserting the cursor at the correct indent
>>> level, but leaving the opening brace where it is.
>>>
>>> The ideal/desired behavior is:
>>>
>>> void Main() {| // opening bracket is typed
>>>
>>> void Main()
>>> {
>>>     |
>>> } // user hits return key, electric-pair-mode pairs up the brackets,
>>> and auto-newline-mode formats the braces correctly
>>>
>>> It would also probably suffice to format with the newline before
>>> hitting enter as well, although I think I prefer hitting enter to open
>>> the block. I'm quite curious as to the internals of these formatting
>>> systems and would be happy to help with a fix/feature if that would be
>>> desired, I am mostly an OCaml programmer but C# is my day job and I've
>>> just recently gotten deeper into Emacs Lisp.
>>>
>>> On Fri, Dec 21, 2018 at 1:49 PM João Távora <joaotavora <at> gmail.com> wrote:
>>> >
>>> > Beatrix Klebe <beeuhtricks <at> gmail.com> writes:
>>> >
>>> > > I believe I saw your Stack Overflow answer about this while searching
>>> > > for the solution. electric-layout-mode works with some quirks, such as
>>> > > that if you put a space after parens in a function definition, the
>>> > > space gets carried on to the newline with that method, which is a bit
>>> > > annoying. What would be ideal, and what I'm looking for, is to get
>>> > > auto-pairing of brackets with braces being placed where they should be
>>> > > automatically and the insertion point getting put in between them at
>>> > > the correct indent level, such as what happens with Visual Studio, or
>>> > > Visual Studio Code, or several other editors with this functionality.
>>> > > Perhaps it is not emacslike to have such behavior be totally
>>> > > automated, but I am used to it and finds it decreases my ordinary
>>> > > levels of frustration when working with verbose and imperative
>>> > > languages. I am currently trying to write some insert specifiers for
>>> > > smartparens to do this, but it is proving more difficult to find an
>>> > > elegant solution than I had expected.
>>> >
>>> > It is quite emacslike (though maybe not activated by default): you just
>>> > have to report the bugs to the Emacs developers as efficiently as
>>> > possible.
>>> >
>>> > 1. Though Alan possibly has already, I still cannot understand the
>>> >    original problem.  Can you start by describing what the buffer looked
>>> >    like before, what you did, what it looked like afterwards, and what
>>> >    you expected it to look like?  If possible start with a clean Emacs
>>> >    -Q recpe.
>>> >
>>> > 2. I have experimented with nicer-playing like alternatives like
>>> >    electric-layout-mode.  I came across a few quirks myself (though I'm
>>> >    not sure if they are the same as yours). So I prepared a patch (in
>>> >    branch scratch/fix-33794-extend-electric-layout-mode) and attached
>>> >    it after the sig.
>>> >
>>> > After loading this patch, in a simple Emacs -Q the configuration:
>>> >
>>> >    (electric-pair-mode)
>>> >    (electric-layout-mode)
>>> >
>>> >    (add-hook 'c-mode-hook
>>> >           (lambda ()
>>> >             (setq-local electric-layout-rules
>>> >                         '((?\{ . after)
>>> >                           (?\{ . after-stay)))))
>>> >
>>> > And, when visiting a C file, if I press `{' I get the expected
>>> > pair+layout+indent behaviour.  Sor example opening a brace after
>>> > int main () gives me:
>>> >
>>> >     int main () {
>>> >         <cursor here>
>>> >     }
>>> >
>>> > I, like Stefan, think cc-mode could/should set electric-layout-rules
>>> > buffer-locally to reflect whatever c-style the user has selected.
>>> >
>>> > Thanks,
>>> > João
>>> >
>>> > PS: Also, can you link to the the relevant to the stack overflow answer you
>>> > mentioned?
>>> >
>>> > commit ab036bdedbb49ecc96d550b5e883e43bb03eaccc
>>> > Author: João Távora <joaotavora <at> gmail.com>
>>> > Date:   Fri Dec 21 18:00:08 2018 +0000
>>> >
>>> >     Extend electric-layout-mode to handle more complex layouts
>>> >
>>> >     Also, have it play nice with electric-pair-mode.
>>> >
>>> >     Multiple matching entries in `electric-layout-rules' are executed in
>>> >     order of appearance.  When inserting a newline in the 'after-stay
>>> >     rule, ensure electric-pair-open-newline-between-pairs is nil.
>>> >
>>> >     Arguably the logic behind electric-pair-open-newline-between-pairs
>>> >     should be moved to electric-layout-mode, but the current rule-matching
>>> >     engine doesn't allow for it.  The current solution seems to be good
>>> >     enough for the situations reported in bug#33794.
>>> >
>>> >     * lisp/electric.el (electric-layout-rules): Adjust docstring.
>>> >     (electric-layout-post-self-insert-function): Loop through rules.  Bind
>>> >     electric-pair-open-newline-between-pairs to nil when handling
>>> >     after-stay.
>>> >
>>> > diff --git a/lisp/electric.el b/lisp/electric.el
>>> > index 6dbf46b80c..6a307a49b9 100644
>>> > --- a/lisp/electric.el
>>> > +++ b/lisp/electric.el
>>> > @@ -370,38 +370,43 @@ electric-layout-rules
>>> >
>>> >  The symbols specify where in relation to CHAR the newline
>>> >  character(s) should be inserted. `after-stay' means insert a
>>> > -newline after CHAR but stay in the same place.")
>>> > +newline after CHAR but stay in the same place.
>>> > +
>>> > +If multiple rules match, they are all executed in order of
>>> > +appearance.")
>>> >
>>> >  (defun electric-layout-post-self-insert-function ()
>>> > -  (let* ((rule (cdr (assq last-command-event electric-layout-rules)))
>>> > -         pos)
>>> > -    (when (and rule
>>> > -               (setq pos (electric--after-char-pos))
>>> > +  (let (pos)
>>> > +    (when (and (setq pos (electric--after-char-pos))
>>> >                 ;; Not in a string or comment.
>>> >                 (not (nth 8 (save-excursion (syntax-ppss pos)))))
>>> > -      (let ((end (point-marker))
>>> > -            (sym (if (functionp rule) (funcall rule) rule)))
>>> > -        (set-marker-insertion-type end (not (eq sym 'after-stay)))
>>> > -        (goto-char pos)
>>> > -        (pcase sym
>>> > -          ;; FIXME: we used `newline' down here which called
>>> > -          ;; self-insert-command and ran post-self-insert-hook recursively.
>>> > -          ;; It happened to make electric-indent-mode work automatically with
>>> > -          ;; electric-layout-mode (at the cost of re-indenting lines
>>> > -          ;; multiple times), but I'm not sure it's what we want.
>>> > -          ;;
>>> > -          ;; FIXME: check eolp before inserting \n?
>>> > -          ('before (goto-char (1- pos)) (skip-chars-backward " \t")
>>> > -                   (unless (bolp) (insert "\n")))
>>> > -          ('after  (insert "\n"))
>>> > -          ('after-stay (save-excursion
>>> > -                         (let ((electric-layout-rules nil))
>>> > -                           (newline 1 t))))
>>> > -          ('around (save-excursion
>>> > -                     (goto-char (1- pos)) (skip-chars-backward " \t")
>>> > -                     (unless (bolp) (insert "\n")))
>>> > -                   (insert "\n")))      ; FIXME: check eolp before inserting \n?
>>> > -        (goto-char end)))))
>>> > +      (goto-char pos)
>>> > +      (dolist (rule electric-layout-rules)
>>> > +        (when (eq last-command-event (car rule))
>>> > +          (let* ((end (point-marker))
>>> > +                 (rule (cdr rule))
>>> > +                 (sym (if (functionp rule) (funcall rule) rule)))
>>> > +            (set-marker-insertion-type end (not (eq sym 'after-stay)))
>>> > +            (pcase sym
>>> > +              ;; FIXME: we used `newline' down here which called
>>> > +              ;; self-insert-command and ran post-self-insert-hook recursively.
>>> > +              ;; It happened to make electric-indent-mode work automatically with
>>> > +              ;; electric-layout-mode (at the cost of re-indenting lines
>>> > +              ;; multiple times), but I'm not sure it's what we want.
>>> > +              ;;
>>> > +              ;; FIXME: check eolp before inserting \n?
>>> > +              ('before (goto-char (1- pos)) (skip-chars-backward " \t")
>>> > +                       (unless (bolp) (insert "\n")))
>>> > +              ('after  (insert "\n"))
>>> > +              ('after-stay (save-excursion
>>> > +                             (let ((electric-layout-rules nil)
>>> > +                                   (electric-pair-open-newline-between-pairs nil))
>>> > +                               (newline 1 t))))
>>> > +              ('around (save-excursion
>>> > +                         (goto-char (1- pos)) (skip-chars-backward " \t")
>>> > +                         (unless (bolp) (insert "\n")))
>>> > +                       (insert "\n")))      ; FIXME: check eolp before inserting \n?
>>> > +            (goto-char end)))))))
>>> >
>>> >  (put 'electric-layout-post-self-insert-function 'priority  40)
>>> >




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sat, 22 Dec 2018 02:17:01 GMT) Full text and rfc822 format available.

Message #47 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: João Távora <joaotavora <at> gmail.com>
To: Beatrix Klebe <beeuhtricks <at> gmail.com>
Cc: Alan Mackenzie <acm <at> muc.de>, bea <at> klebe.blog,
 Stefan Monnier <monnier <at> iro.umontreal.ca>, 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1;
 electric-pair-mode breaks auto-newline minor mode of cc-mode
Date: Sat, 22 Dec 2018 02:16:03 +0000
[Message part 1 (text/plain, inline)]
Hi again Beatrix,

In the latest version of the patch I am preparing, if you do

    (add-hook 'c-mode-hook
	      (lambda ()
		(setq-local electric-layout-rules
			    '((?\{ . before})
                              (?\{ . after)
			      (?\{ . after-stay)))))

You should arive at Allman C-style electric layouts.  So typing
int main () <spaces> then brace should give you:

int main ()
{
  <cursor here>
}

I attach the two patches for convenience, which you can also find in the
scratch/fix-33794-extend-electric-layout-mode branch.

João

[0001-Extend-electric-layout-mode-to-handle-more-complex-l.patch (text/x-diff, inline)]
From ab036bdedbb49ecc96d550b5e883e43bb03eaccc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= <joaotavora <at> gmail.com>
Date: Fri, 21 Dec 2018 18:00:08 +0000
Subject: [PATCH 1/2] Extend electric-layout-mode to handle more complex
 layouts

Also, have it play nice with electric-pair-mode.

Multiple matching entries in `electric-layout-rules' are executed in
order of appearance.  When inserting a newline in the 'after-stay
rule, ensure electric-pair-open-newline-between-pairs is nil.

Arguably the logic behind electric-pair-open-newline-between-pairs
should be moved to electric-layout-mode, but the current rule-matching
engine doesn't allow for it.  The current solution seems to be good
enough for the situations reported in bug#33794.

* lisp/electric.el (electric-layout-rules): Adjust docstring.
(electric-layout-post-self-insert-function): Loop through rules.  Bind
electric-pair-open-newline-between-pairs to nil when handling
after-stay.
---
 lisp/electric.el | 61 ++++++++++++++++++++++++++----------------------
 1 file changed, 33 insertions(+), 28 deletions(-)

diff --git a/lisp/electric.el b/lisp/electric.el
index 6dbf46b80c..6a307a49b9 100644
--- a/lisp/electric.el
+++ b/lisp/electric.el
@@ -370,38 +370,43 @@ electric-layout-rules
 
 The symbols specify where in relation to CHAR the newline
 character(s) should be inserted. `after-stay' means insert a
-newline after CHAR but stay in the same place.")
+newline after CHAR but stay in the same place.
+
+If multiple rules match, they are all executed in order of
+appearance.")
 
 (defun electric-layout-post-self-insert-function ()
-  (let* ((rule (cdr (assq last-command-event electric-layout-rules)))
-         pos)
-    (when (and rule
-               (setq pos (electric--after-char-pos))
+  (let (pos)
+    (when (and (setq pos (electric--after-char-pos))
                ;; Not in a string or comment.
                (not (nth 8 (save-excursion (syntax-ppss pos)))))
-      (let ((end (point-marker))
-            (sym (if (functionp rule) (funcall rule) rule)))
-        (set-marker-insertion-type end (not (eq sym 'after-stay)))
-        (goto-char pos)
-        (pcase sym
-          ;; FIXME: we used `newline' down here which called
-          ;; self-insert-command and ran post-self-insert-hook recursively.
-          ;; It happened to make electric-indent-mode work automatically with
-          ;; electric-layout-mode (at the cost of re-indenting lines
-          ;; multiple times), but I'm not sure it's what we want.
-          ;;
-          ;; FIXME: check eolp before inserting \n?
-          ('before (goto-char (1- pos)) (skip-chars-backward " \t")
-                   (unless (bolp) (insert "\n")))
-          ('after  (insert "\n"))
-          ('after-stay (save-excursion
-                         (let ((electric-layout-rules nil))
-                           (newline 1 t))))
-          ('around (save-excursion
-                     (goto-char (1- pos)) (skip-chars-backward " \t")
-                     (unless (bolp) (insert "\n")))
-                   (insert "\n")))      ; FIXME: check eolp before inserting \n?
-        (goto-char end)))))
+      (goto-char pos)
+      (dolist (rule electric-layout-rules)
+        (when (eq last-command-event (car rule))
+          (let* ((end (point-marker))
+                 (rule (cdr rule))
+                 (sym (if (functionp rule) (funcall rule) rule)))
+            (set-marker-insertion-type end (not (eq sym 'after-stay)))
+            (pcase sym
+              ;; FIXME: we used `newline' down here which called
+              ;; self-insert-command and ran post-self-insert-hook recursively.
+              ;; It happened to make electric-indent-mode work automatically with
+              ;; electric-layout-mode (at the cost of re-indenting lines
+              ;; multiple times), but I'm not sure it's what we want.
+              ;;
+              ;; FIXME: check eolp before inserting \n?
+              ('before (goto-char (1- pos)) (skip-chars-backward " \t")
+                       (unless (bolp) (insert "\n")))
+              ('after  (insert "\n"))
+              ('after-stay (save-excursion
+                             (let ((electric-layout-rules nil)
+                                   (electric-pair-open-newline-between-pairs nil))
+                               (newline 1 t))))
+              ('around (save-excursion
+                         (goto-char (1- pos)) (skip-chars-backward " \t")
+                         (unless (bolp) (insert "\n")))
+                       (insert "\n")))      ; FIXME: check eolp before inserting \n?
+            (goto-char end)))))))
 
 (put 'electric-layout-post-self-insert-function 'priority  40)
 
-- 
2.20.0

[0002-Rework-electric-layout-post-self-insert-function-bug.patch (text/x-diff, inline)]
From dfc19a04f5f455051d158648a963cb1fd8b91c67 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= <joaotavora <at> gmail.com>
Date: Sat, 22 Dec 2018 01:52:08 +0000
Subject: [PATCH 2/2] Rework electric-layout-post-self-insert-function
 (bug#33794)

This should now fix more problems reported in (bug#33794) regarding
insertion of newlines before and after the opening brace.  Write two
automated tests.

Also provide a new electric-layout-local-mode for testing.

* lisp/electric.el (electric-layout-post-self-insert-function-1):
New function that does the work for
electric-layout-post-self-insert-function-1.
(electric-layout-local-mode): New minor mode.

* test/lisp/electric-tests.el (electric-layout-int-main-kernel-style)
(electric-layout-int-main-allman-style): Add two tests.
---
 lisp/electric.el            | 49 +++++++++++++++++++++++++------------
 test/lisp/electric-tests.el | 34 +++++++++++++++++++++++++
 2 files changed, 68 insertions(+), 15 deletions(-)

diff --git a/lisp/electric.el b/lisp/electric.el
index 6a307a49b9..24c040d05b 100644
--- a/lisp/electric.el
+++ b/lisp/electric.el
@@ -376,17 +376,25 @@ electric-layout-rules
 appearance.")
 
 (defun electric-layout-post-self-insert-function ()
-  (let (pos)
+  (when electric-layout-mode
+    (electric-layout-post-self-insert-function-1)))
+
+;; for edebug's sake a separate function
+(defun electric-layout-post-self-insert-function-1 ()
+  (let (pos end)
     (when (and (setq pos (electric--after-char-pos))
                ;; Not in a string or comment.
                (not (nth 8 (save-excursion (syntax-ppss pos)))))
       (goto-char pos)
+      (setq end (point-marker))
       (dolist (rule electric-layout-rules)
         (when (eq last-command-event (car rule))
-          (let* ((end (point-marker))
-                 (rule (cdr rule))
-                 (sym (if (functionp rule) (funcall rule) rule)))
-            (set-marker-insertion-type end (not (eq sym 'after-stay)))
+          (let* ((rule (cdr rule))
+                 (sym (if (functionp rule) (funcall rule) rule))
+                 (nl (lambda ()
+                       (let ((electric-layout-mode nil)
+                             (electric-pair-open-newline-between-pairs nil))
+                               (newline 1 t)))))
             (pcase sym
               ;; FIXME: we used `newline' down here which called
               ;; self-insert-command and ran post-self-insert-hook recursively.
@@ -395,18 +403,16 @@ electric-layout-post-self-insert-function
               ;; multiple times), but I'm not sure it's what we want.
               ;;
               ;; FIXME: check eolp before inserting \n?
-              ('before (goto-char (1- pos)) (skip-chars-backward " \t")
-                       (unless (bolp) (insert "\n")))
-              ('after  (insert "\n"))
-              ('after-stay (save-excursion
-                             (let ((electric-layout-rules nil)
-                                   (electric-pair-open-newline-between-pairs nil))
-                               (newline 1 t))))
+              ('before (save-excursion
+                         (goto-char (1- pos)) (skip-chars-backward " \t")
+                         (unless (bolp) (funcall nl))))
+              ('after  (funcall nl))
+              ('after-stay (save-excursion (funcall nl)))
               ('around (save-excursion
                          (goto-char (1- pos)) (skip-chars-backward " \t")
-                         (unless (bolp) (insert "\n")))
-                       (insert "\n")))      ; FIXME: check eolp before inserting \n?
-            (goto-char end)))))))
+                         (unless (bolp) (funcall nl)))
+                       (funcall nl)))      ; FIXME: check eolp before inserting \n?
+            ))))))
 
 (put 'electric-layout-post-self-insert-function 'priority  40)
 
@@ -424,6 +430,19 @@ electric-layout-mode
          (remove-hook 'post-self-insert-hook
                       #'electric-layout-post-self-insert-function))))
 
+;;;###autoload
+(define-minor-mode electric-layout-local-mode
+  "Toggle `electric-layout-mode' only in this buffer."
+  :variable (buffer-local-value 'electric-layout-mode (current-buffer))
+  (cond
+   ((eq electric-layout-mode (default-value 'electric-layout-mode))
+    (kill-local-variable 'electric-layout-mode))
+   ((not (default-value 'electric-layout-mode))
+    ;; Locally enabled, but globally disabled.
+    (electric-layout-mode 1)		  ; Setup the hooks.
+    (setq-default electric-layout-mode nil) ; But keep it globally disabled.
+    )))
+
 ;;; Electric quoting.
 
 (defcustom electric-quote-comment t
diff --git a/test/lisp/electric-tests.el b/test/lisp/electric-tests.el
index a665d2eb28..971c3e9567 100644
--- a/test/lisp/electric-tests.el
+++ b/test/lisp/electric-tests.el
@@ -812,5 +812,39 @@ electric-quote-markdown-in-code
   :bindings '((comment-start . "<!--") (comment-use-syntax . t))
   :test-in-comments nil :test-in-strings nil)
 
+
+;;; tests for `electric-layout-mode'
+
+(ert-deftest electric-layout-int-main-kernel-style ()
+  (save-electric-modes
+    (ert-with-test-buffer ()
+      (c-mode)
+      (electric-layout-local-mode 1)
+      (electric-pair-local-mode 1)
+      (electric-indent-local-mode 1)
+      (setq-local electric-layout-rules
+              '((?\{ . after)
+                (?\{ . after-stay)))
+      (insert "int main () ")
+      (let ((last-command-event ?\{))
+        (call-interactively (key-binding `[,last-command-event])))
+      (should (equal (buffer-string) "int main () {\n  \n}")))))
+
+(ert-deftest electric-layout-int-main-allman-style ()
+  (save-electric-modes
+    (ert-with-test-buffer ()
+      (c-mode)
+      (electric-layout-local-mode 1)
+      (electric-pair-local-mode 1)
+      (electric-indent-local-mode 1)
+      (setq-local electric-layout-rules
+              '((?\{ . before)
+                (?\{ . after)
+                (?\{ . after-stay)))
+      (insert "int main () ")
+      (let ((last-command-event ?\{))
+        (call-interactively (key-binding `[,last-command-event])))
+      (should (equal (buffer-string) "int main ()\n{\n  \n}")))))
+
 (provide 'electric-tests)
 ;;; electric-tests.el ends here
-- 
2.20.0

[Message part 4 (text/plain, inline)]




João Távora <joaotavora <at> gmail.com> writes:

> Beatrix Klebe <beeuhtricks <at> gmail.com> writes:
>
>> I know how to do hotpaches but that doesn't appear to solve the
>> problem I'm having here, unless I've missed something. The problem is
>> with moving the opening bracket, not the insertion point.
>
> Beatrix,
>
> I think you may have missed the fact that I am suggesting alternatives
> that:
>
> * involve cc-mode, or one of its derived modes;
>
> * don't involve M-x c-toggle-auto-newline (turning on what you call
>   auto-newline-mode);
>
> * involve turning on the global electric-layout-mode and a thin
>   customization for it in the buffers where you think it's relevant
>   (presumably cc-mode);
>
> * may involve multiple fixed/patched versions of lisp/electric.el as I
>   understand your problem(s);
>
> As it stands, the last patch I sent you passes my only test which is
> this:  given a file 33794.el which is just:
>
>    (electric-pair-mode)
>    (electric-layout-mode)
>     
>    (add-hook 'c-mode-hook
>              (lambda ()
>                (setq-local electric-layout-rules
>                            '((?\{ . after)
>                              (?\{ . after-stay)))))
>
>
> then running this from a shell:
>
>    $ emacs -Q -l 33794.el something.c
>
> Opens a new c-mode buffer.  Type 'int main ()' and then an opening
> brace.  You should get:
>
>    int main () {
>        <cursor>
>    }
>
> Can you reproduce these results?  If you can come up with more of these
> tests written in this or a similarly simple and exact manner it's easier
> for me to understand what's going on (it's also easier to write
> automated tests).
>
> João
>
>>
>>
>> On Fri, Dec 21, 2018 at 2:20 PM João Távora <joaotavora <at> gmail.com> wrote:
>>>
>>> Hi Beatrix,
>>>
>>> The solution I propose involves introducing the hotpatch I attached
>>> to fix electric-layout-mode in your emacs, so I wouldn't expect it
>>> to work if you haven't done that.
>>>
>>> Do you know how to do it?
>>>
>>> Though Alan will probably suggest otherwise, I'd also steer away
>>> from c-specific functionality and keep to the triad
>>> electric-indent-mode, electric-pair-mode and electric-indent-mode,
>>> at least while we try to extend/fix these modes to accommodate your
>>> needs.
>>>
>>> After such a solution is evaluated, you can select to keep it or move to something else.
>>>
>>> João
>>>
>>> On Fri, Dec 21, 2018, 19:06 Beatrix Klebe <beeuhtricks <at> gmail.com wrote:
>>>>
>>>> Here's the link, I believe it was Stefan that answered it:
>>>> https://emacs.stackexchange.com/questions/2837/automatically-formatting-brackets/2853#2853
>>>>
>>>> I have tried this with emacs -Q and it does not fix the issue, which
>>>> is as follows.
>>>>
>>>> Ordinarily in cc-mode when you have auto-newline-mode activated, and
>>>> as far as I can tell, a cc-mode configuration that supports it, (which
>>>> csharp-mode contains), the following happens when opening a block
>>>> (pipe is the cursor):
>>>>
>>>> void Main() {| // opening bracket is typed
>>>>
>>>> becomes
>>>>
>>>> void Main
>>>> {
>>>>     |
>>>>
>>>> when c-toggle-auto-newline is activated. However, if you also want
>>>> your braces automatically paired, with electric-pair-mode, instead the
>>>> following occurs:
>>>>
>>>> void Main() {| // opening bracket is typed
>>>>
>>>> void Main() {|} // electric-pair-mode closes the open bracket, but
>>>> auto-newline-mode does not appear to do anything.
>>>>
>>>> void Main() {
>>>>     |
>>>> } // user hits return, inserting the cursor at the correct indent
>>>> level, but leaving the opening brace where it is.
>>>>
>>>> The ideal/desired behavior is:
>>>>
>>>> void Main() {| // opening bracket is typed
>>>>
>>>> void Main()
>>>> {
>>>>     |
>>>> } // user hits return key, electric-pair-mode pairs up the brackets,
>>>> and auto-newline-mode formats the braces correctly
>>>>
>>>> It would also probably suffice to format with the newline before
>>>> hitting enter as well, although I think I prefer hitting enter to open
>>>> the block. I'm quite curious as to the internals of these formatting
>>>> systems and would be happy to help with a fix/feature if that would be
>>>> desired, I am mostly an OCaml programmer but C# is my day job and I've
>>>> just recently gotten deeper into Emacs Lisp.
>>>>
>>>> On Fri, Dec 21, 2018 at 1:49 PM João Távora <joaotavora <at> gmail.com> wrote:
>>>> >
>>>> > Beatrix Klebe <beeuhtricks <at> gmail.com> writes:
>>>> >
>>>> > > I believe I saw your Stack Overflow answer about this while searching
>>>> > > for the solution. electric-layout-mode works with some quirks, such as
>>>> > > that if you put a space after parens in a function definition, the
>>>> > > space gets carried on to the newline with that method, which is a bit
>>>> > > annoying. What would be ideal, and what I'm looking for, is to get
>>>> > > auto-pairing of brackets with braces being placed where they should be
>>>> > > automatically and the insertion point getting put in between them at
>>>> > > the correct indent level, such as what happens with Visual Studio, or
>>>> > > Visual Studio Code, or several other editors with this functionality.
>>>> > > Perhaps it is not emacslike to have such behavior be totally
>>>> > > automated, but I am used to it and finds it decreases my ordinary
>>>> > > levels of frustration when working with verbose and imperative
>>>> > > languages. I am currently trying to write some insert specifiers for
>>>> > > smartparens to do this, but it is proving more difficult to find an
>>>> > > elegant solution than I had expected.
>>>> >
>>>> > It is quite emacslike (though maybe not activated by default): you just
>>>> > have to report the bugs to the Emacs developers as efficiently as
>>>> > possible.
>>>> >
>>>> > 1. Though Alan possibly has already, I still cannot understand the
>>>> >    original problem.  Can you start by describing what the buffer looked
>>>> >    like before, what you did, what it looked like afterwards, and what
>>>> >    you expected it to look like?  If possible start with a clean Emacs
>>>> >    -Q recpe.
>>>> >
>>>> > 2. I have experimented with nicer-playing like alternatives like
>>>> >    electric-layout-mode.  I came across a few quirks myself (though I'm
>>>> >    not sure if they are the same as yours). So I prepared a patch (in
>>>> >    branch scratch/fix-33794-extend-electric-layout-mode) and attached
>>>> >    it after the sig.
>>>> >
>>>> > After loading this patch, in a simple Emacs -Q the configuration:
>>>> >
>>>> >    (electric-pair-mode)
>>>> >    (electric-layout-mode)
>>>> >
>>>> >    (add-hook 'c-mode-hook
>>>> >           (lambda ()
>>>> >             (setq-local electric-layout-rules
>>>> >                         '((?\{ . after)
>>>> >                           (?\{ . after-stay)))))
>>>> >
>>>> > And, when visiting a C file, if I press `{' I get the expected
>>>> > pair+layout+indent behaviour.  Sor example opening a brace after
>>>> > int main () gives me:
>>>> >
>>>> >     int main () {
>>>> >         <cursor here>
>>>> >     }
>>>> >
>>>> > I, like Stefan, think cc-mode could/should set electric-layout-rules
>>>> > buffer-locally to reflect whatever c-style the user has selected.
>>>> >
>>>> > Thanks,
>>>> > João
>>>> >
>>>> > PS: Also, can you link to the the relevant to the stack overflow answer you
>>>> > mentioned?
>>>> >
>>>> > commit ab036bdedbb49ecc96d550b5e883e43bb03eaccc
>>>> > Author: João Távora <joaotavora <at> gmail.com>
>>>> > Date:   Fri Dec 21 18:00:08 2018 +0000
>>>> >
>>>> >     Extend electric-layout-mode to handle more complex layouts
>>>> >
>>>> >     Also, have it play nice with electric-pair-mode.
>>>> >
>>>> >     Multiple matching entries in `electric-layout-rules' are executed in
>>>> >     order of appearance.  When inserting a newline in the 'after-stay
>>>> >     rule, ensure electric-pair-open-newline-between-pairs is nil.
>>>> >
>>>> >     Arguably the logic behind electric-pair-open-newline-between-pairs
>>>> >     should be moved to electric-layout-mode, but the current rule-matching
>>>> >     engine doesn't allow for it.  The current solution seems to be good
>>>> >     enough for the situations reported in bug#33794.
>>>> >
>>>> >     * lisp/electric.el (electric-layout-rules): Adjust docstring.
>>>> >     (electric-layout-post-self-insert-function): Loop through rules.  Bind
>>>> >     electric-pair-open-newline-between-pairs to nil when handling
>>>> >     after-stay.
>>>> >
>>>> > diff --git a/lisp/electric.el b/lisp/electric.el
>>>> > index 6dbf46b80c..6a307a49b9 100644
>>>> > --- a/lisp/electric.el
>>>> > +++ b/lisp/electric.el
>>>> > @@ -370,38 +370,43 @@ electric-layout-rules
>>>> >
>>>> >  The symbols specify where in relation to CHAR the newline
>>>> >  character(s) should be inserted. `after-stay' means insert a
>>>> > -newline after CHAR but stay in the same place.")
>>>> > +newline after CHAR but stay in the same place.
>>>> > +
>>>> > +If multiple rules match, they are all executed in order of
>>>> > +appearance.")
>>>> >
>>>> >  (defun electric-layout-post-self-insert-function ()
>>>> > -  (let* ((rule (cdr (assq last-command-event electric-layout-rules)))
>>>> > -         pos)
>>>> > -    (when (and rule
>>>> > -               (setq pos (electric--after-char-pos))
>>>> > +  (let (pos)
>>>> > +    (when (and (setq pos (electric--after-char-pos))
>>>> >                 ;; Not in a string or comment.
>>>> >                 (not (nth 8 (save-excursion (syntax-ppss pos)))))
>>>> > -      (let ((end (point-marker))
>>>> > -            (sym (if (functionp rule) (funcall rule) rule)))
>>>> > -        (set-marker-insertion-type end (not (eq sym 'after-stay)))
>>>> > -        (goto-char pos)
>>>> > -        (pcase sym
>>>> > -          ;; FIXME: we used `newline' down here which called
>>>> > -          ;; self-insert-command and ran post-self-insert-hook recursively.
>>>> > -          ;; It happened to make electric-indent-mode work automatically with
>>>> > -          ;; electric-layout-mode (at the cost of re-indenting lines
>>>> > -          ;; multiple times), but I'm not sure it's what we want.
>>>> > -          ;;
>>>> > -          ;; FIXME: check eolp before inserting \n?
>>>> > -          ('before (goto-char (1- pos)) (skip-chars-backward " \t")
>>>> > -                   (unless (bolp) (insert "\n")))
>>>> > -          ('after  (insert "\n"))
>>>> > -          ('after-stay (save-excursion
>>>> > -                         (let ((electric-layout-rules nil))
>>>> > -                           (newline 1 t))))
>>>> > -          ('around (save-excursion
>>>> > -                     (goto-char (1- pos)) (skip-chars-backward " \t")
>>>> > -                     (unless (bolp) (insert "\n")))
>>>> > -                   (insert "\n")))      ; FIXME: check eolp before inserting \n?
>>>> > -        (goto-char end)))))
>>>> > +      (goto-char pos)
>>>> > +      (dolist (rule electric-layout-rules)
>>>> > +        (when (eq last-command-event (car rule))
>>>> > +          (let* ((end (point-marker))
>>>> > +                 (rule (cdr rule))
>>>> > +                 (sym (if (functionp rule) (funcall rule) rule)))
>>>> > +            (set-marker-insertion-type end (not (eq sym 'after-stay)))
>>>> > +            (pcase sym
>>>> > +              ;; FIXME: we used `newline' down here which called
>>>> > +              ;; self-insert-command and ran post-self-insert-hook recursively.
>>>> > +              ;; It happened to make electric-indent-mode work automatically with
>>>> > +              ;; electric-layout-mode (at the cost of re-indenting lines
>>>> > +              ;; multiple times), but I'm not sure it's what we want.
>>>> > +              ;;
>>>> > +              ;; FIXME: check eolp before inserting \n?
>>>> > +              ('before (goto-char (1- pos)) (skip-chars-backward " \t")
>>>> > +                       (unless (bolp) (insert "\n")))
>>>> > +              ('after  (insert "\n"))
>>>> > +              ('after-stay (save-excursion
>>>> > +                             (let ((electric-layout-rules nil)
>>>> > +                                   (electric-pair-open-newline-between-pairs nil))
>>>> > +                               (newline 1 t))))
>>>> > +              ('around (save-excursion
>>>> > +                         (goto-char (1- pos)) (skip-chars-backward " \t")
>>>> > +                         (unless (bolp) (insert "\n")))
>>>> > +                       (insert "\n")))      ; FIXME: check eolp before inserting \n?
>>>> > +            (goto-char end)))))))
>>>> >
>>>> >  (put 'electric-layout-post-self-insert-function 'priority  40)
>>>> >

Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sat, 22 Dec 2018 02:49:02 GMT) Full text and rfc822 format available.

Message #50 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: Beatrix Klebe <beeuhtricks <at> gmail.com>
Cc: 33794 <at> debbugs.gnu.org, bea <at> klebe.blog,
 João Távora <joaotavora <at> gmail.com>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Sat, 22 Dec 2018 02:41:43 +0000
Hello, Beatrix.

As maintainer of CC Mode, I earnestly recommend you NOT to follow João's
suggestion.  It will not work, and will waste your time.  Even if it
appears to work, you will end up picking out bugs for an indeterminate
period.

Basically, electric-pair-mode as it is currently built is incompatible
with CC Mode, as I have pointed out here, albeit somewhat
undiplomatically.

I suggest you do nothing until tempers amongst Emacs developers have
cooled down, and hopefully a genuine solution to the bug has been worked
out and implemented.

-- 
Alan Mackenzie (Nuremberg, Germany).



On Sat, Dec 22, 2018 at 02:16:03 +0000, João Távora wrote:
> Hi again Beatrix,

> In the latest version of the patch I am preparing, if you do

>     (add-hook 'c-mode-hook
> 	      (lambda ()
> 		(setq-local electric-layout-rules
> 			    '((?\{ . before})
>                               (?\{ . after)
> 			      (?\{ . after-stay)))))

> You should arive at Allman C-style electric layouts.  So typing
> int main () <spaces> then brace should give you:

> int main ()
> {
>   <cursor here>
> }

> I attach the two patches for convenience, which you can also find in the
> scratch/fix-33794-extend-electric-layout-mode branch.

> João




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sat, 22 Dec 2018 03:23:01 GMT) Full text and rfc822 format available.

Message #53 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: João Távora <joaotavora <at> gmail.com>
To: Alan Mackenzie <acm <at> muc.de>
Cc: Beatrix Klebe <beeuhtricks <at> gmail.com>, bea <at> klebe.blog,
 Stefan Monnier <monnier <at> iro.umontreal.ca>, 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1;
 electric-pair-mode breaks auto-newline minor mode of cc-mode
Date: Sat, 22 Dec 2018 03:22:47 +0000
Alan Mackenzie <acm <at> muc.de> writes:

> Hello, Beatrix.
>
> As maintainer of CC Mode, I earnestly recommend you NOT to follow João's
> suggestion.  It will not work, and will waste your time.

What, exactly, will not work?

> Even if it appears to work, you will end up picking out bugs for an
> indeterminate period.

What bugs?  If you know of any, it would be good to report them, right?

> Basically, electric-pair-mode as it is currently built is incompatible
> with CC Mode, as I have pointed out here, albeit somewhat
> undiplomatically.
>
> I suggest you do nothing until tempers amongst Emacs developers have
> cooled down, and hopefully a genuine solution to the bug has been worked
> out and implemented.

If you don't like electric-layout-mode, don't use it.  I'm trying to
develop an alternative to c-toggle-auto-newline within the
electric-*-mode frame.  It's an experiment which I don't even know if
Stefan will agree to, but it seems to work.  If Beatrix wants to
cooperate, why shouldn't she?

I'm not asking you to nuke c-toggle-auto-newline or anything, but should
we all be forced to use it?  I don't think it's sensible in a free
software project, Alan (and my temper is quite cool when saying this
:-))

Again, I said I don't have anything against making eletric-pair-mode
compatible with c-toggle-auto-newline if someone comes up with a good
solution that doesn't break e-p-m for other modes.  I will not invest
time in looking into that solution, but you or someone else may, of
course.

In the meantime let people explore alternatives, right?

João




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sat, 22 Dec 2018 04:42:02 GMT) Full text and rfc822 format available.

Message #56 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Beatrix Klebe <beeuhtricks <at> gmail.com>
To: João Távora <joaotavora <at> gmail.com>
Cc: Alan Mackenzie <acm <at> muc.de>, bea <at> klebe.blog, 33794 <at> debbugs.gnu.org,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Fri, 21 Dec 2018 23:41:38 -0500
[Message part 1 (text/plain, inline)]
I didn’t intend to kick the hornet’s nest of ideological factions here, I
was honestly just wondering if this was actually expected behavior of these
two modes together and if not if the fix was trivial. The answer seems to
be that it is indeed a bug and the fix is non-trivial, and furthermore
while I appreciate attempts to hotfix it, those are not solutions of the
quality I was expecting, (I encountered those already while doing my own
research before I filed this bug report and I found them unsatisfactory
both then and now) and furthermore I feel like I should be open in stating
that I feel somewhat condescended to. I know what c-toggle-auto-newline is,
I also know that functions prefixed with “toggle” are functions that toggle
a mode or setting internally, in this case a minor mode called auto-newline
(
https://www.gnu.org/software/emacs/manual/html_node/ccmode/Auto_002dnewlines.html)
I was about five minutes away from diving into the source of these two
packages to fix it myself, as I have spent probably 10 hours reasearching
this problem at this point. I’m sorry if I misunderstood something, I was
mainly looking for clarification that what I was experiencing was a bug,
and it is beginning to seem like there is none to be had here. My
apologies.

On Fri, Dec 21, 2018 at 10:22 PM João Távora <joaotavora <at> gmail.com> wrote:

> Alan Mackenzie <acm <at> muc.de> writes:
>
> > Hello, Beatrix.
> >
> > As maintainer of CC Mode, I earnestly recommend you NOT to follow João's
> > suggestion.  It will not work, and will waste your time.
>
> What, exactly, will not work?
>
> > Even if it appears to work, you will end up picking out bugs for an
> > indeterminate period.
>
> What bugs?  If you know of any, it would be good to report them, right?
>
> > Basically, electric-pair-mode as it is currently built is incompatible
> > with CC Mode, as I have pointed out here, albeit somewhat
> > undiplomatically.
> >
> > I suggest you do nothing until tempers amongst Emacs developers have
> > cooled down, and hopefully a genuine solution to the bug has been worked
> > out and implemented.
>
> If you don't like electric-layout-mode, don't use it.  I'm trying to
> develop an alternative to c-toggle-auto-newline within the
> electric-*-mode frame.  It's an experiment which I don't even know if
> Stefan will agree to, but it seems to work.  If Beatrix wants to
> cooperate, why shouldn't she?
>
> I'm not asking you to nuke c-toggle-auto-newline or anything, but should
> we all be forced to use it?  I don't think it's sensible in a free
> software project, Alan (and my temper is quite cool when saying this
> :-))
>
> Again, I said I don't have anything against making eletric-pair-mode
> compatible with c-toggle-auto-newline if someone comes up with a good
> solution that doesn't break e-p-m for other modes.  I will not invest
> time in looking into that solution, but you or someone else may, of
> course.
>
> In the meantime let people explore alternatives, right?
>
> João
>
[Message part 2 (text/html, inline)]

Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sat, 22 Dec 2018 10:03:01 GMT) Full text and rfc822 format available.

Message #59 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: João Távora <joaotavora <at> gmail.com>
To: Beatrix Klebe <beeuhtricks <at> gmail.com>
Cc: Alan Mackenzie <acm <at> muc.de>, bea <at> klebe.blog, 33794 <at> debbugs.gnu.org,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#33794: 26.1;
 electric-pair-mode breaks auto-newline minor mode of cc-mode
Date: Sat, 22 Dec 2018 10:02:07 +0000
Beatrix Klebe <beeuhtricks <at> gmail.com> writes:

> I didn’t intend to kick the hornet’s nest of ideological factions

You kinda did, but it's in their nature to be kicked.

> here, I was honestly just wondering if this was actually expected
> behavior of these two modes together and if not if the fix was
> trivial. The answer seems to be that it is indeed a bug and the fix is
> non-trivial,

All correct.

> and furthermore while I appreciate attempts to hotfix it, those are
> not solutions of the quality I was expecting

 Can you specify what is missing in terms of quality? 

> , (I encountered those already while doing my own research before I
> filed this bug report and I found them unsatisfactory both then and
> now) and furthermore I feel like I should be open in stating that I
> feel somewhat condescended to.

I'm very sorry about that, it was never my intention (please read
below).

> I know what c-toggle-auto-newline is, I also know that functions
> prefixed with “toggle” are functions that toggle a mode or setting
> internally, in this case a minor mode called auto-newline
> (https://www.gnu.org/software/emacs/manual/html_node/ccmode/Auto_002dnewlines.html)

After following the link you gave me: I see the misunderstanding.  You
see, even though CC-mode's manual says "auto-newline" is a minor mode,
it's not.  It's just a variation on the major-mode's behaviour (in fact
the CC-mode manual clarifies it here[1] as a "minor-mode-like feature",
but the misunderstanding remained). There's no M-x auto-newline-mode to
be invoked and no (define-minor-mode auto-newline-mode...) to be found
in the code.  Mentions to this as a minor mode are only found in the
manual (a documentation bug, in my opinion).

So this is why I was so specific with M-x c-toggle-auto-newline,
becausen that's the actual command that someone who doesn't use it needs
to turn on that pseudo-minor-mode: Without it, I couldn't observe the
behaviour that you reported. With it, you couldn't experience the
solution I was giving you.

> I was about five minutes away from diving into the source of these two
> packages to fix it myself, as I have spent probably 10 hours
> reasearching this problem at this point. I’m sorry if I misunderstood
> something, I was mainly looking for clarification that what I was
> experiencing was a bug, and it is beginning to seem like there is none
> to be had here.

OK I'll clarify: There is a bug: there are two diverging views on how to
fix it because there are diverging views about where it lies in Emacs:

* The only available fix so far (mine) is still experimental.  I would
  appreciate your feedback but it's perfectly OK to go spend your time
  elsewhere because there's a risk that it won't make it in the end.

  In this fix, I'm not targetting Alan's code: I am extending an
  existing, separate feature that could render some of CC-mode's
  functionality, specifically the peudo auto-newline-mode, obsolete.

* The other fix isn't available yet, in experimental or final form.
  Presumably it would target electric-pair-mode.  If Alan, you, or
  someone else wants to work on it, that's quite alright, but beware
  that electric-pair-mode must work for all major modes (including
  things like minibuffers and REPLs), not just CC-mode.

Regards,
João

[1]: https://www.gnu.org/software/emacs/manual/html_node/ccmode/Minor-Modes.html#Minor-Modes


>
> On Fri, Dec 21, 2018 at 10:22 PM João Távora <joaotavora <at> gmail.com> wrote:
>
>  Alan Mackenzie <acm <at> muc.de> writes:
>
>  > Hello, Beatrix.
>  >
>  > As maintainer of CC Mode, I earnestly recommend you NOT to follow João's
>  > suggestion.  It will not work, and will waste your time.
>
>  What, exactly, will not work?
>
>  > Even if it appears to work, you will end up picking out bugs for an
>  > indeterminate period.
>
>  What bugs?  If you know of any, it would be good to report them, right?
>
>  > Basically, electric-pair-mode as it is currently built is incompatible
>  > with CC Mode, as I have pointed out here, albeit somewhat
>  > undiplomatically.
>  >
>  > I suggest you do nothing until tempers amongst Emacs developers have
>  > cooled down, and hopefully a genuine solution to the bug has been worked
>  > out and implemented.
>
>  If you don't like electric-layout-mode, don't use it.  I'm trying to
>  develop an alternative to c-toggle-auto-newline within the
>  electric-*-mode frame.  It's an experiment which I don't even know if
>  Stefan will agree to, but it seems to work.  If Beatrix wants to
>  cooperate, why shouldn't she?
>
>  I'm not asking you to nuke c-toggle-auto-newline or anything, but should
>  we all be forced to use it?  I don't think it's sensible in a free
>  software project, Alan (and my temper is quite cool when saying this
>  :-))
>
>  Again, I said I don't have anything against making eletric-pair-mode
>  compatible with c-toggle-auto-newline if someone comes up with a good
>  solution that doesn't break e-p-m for other modes.  I will not invest
>  time in looking into that solution, but you or someone else may, of
>  course.
>
>  In the meantime let people explore alternatives, right?
>
>  João




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sat, 22 Dec 2018 10:27:02 GMT) Full text and rfc822 format available.

Message #62 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: João Távora <joaotavora <at> gmail.com>
Cc: bea <at> klebe.blog, Stefan Monnier <monnier <at> IRO.UMontreal.CA>,
 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Sat, 22 Dec 2018 10:20:11 +0000
Hello, João

On Sat, Dec 22, 2018 at 00:45:20 +0000, João Távora wrote:

> Hi Alan,

> I will be replying to the two emails you sent me in this single message.

> Alan Mackenzie <acm <at> muc.de> writes:

> > No, not at all.  CC Mode has been working for several decades, and works
> > well.  electric-pair-mode is the new kid on the block, just a few years
> > old, and was apparently hacked together without regard to some well
> > established conventions.  It should have provided interfaces to allow
> > existing software to connect to it - for example a variable to contain a
> > function to insert the electric character, or something like that.
> > Maybe.  It should have been considered, but apparently wasn't.

> First, I think you'll agree that antiquity is a poor measure of the
> merits of software.

Here we have antiquity, combined with software actually being used
combined with a lack of bugs.  (I'm talking about CC Mode's auto-newline
facility, here).  This SW is good.

> Here's a characteristic of electric-pair-mode that I think is an
> actual merit: it works for every mode in Emacs..

This clearly isn't true at the moment.  Have you tested it with, for
example, Cperl Mode, or Vera Mode?  That characteristic is an
aspiration, which is laudable.

> Also, I don't know if you understand the history of electric-pair-mode.
> It has two generations: One, before 24.4, which I believe Stefan wrote,
> where it was a simpler mode to automatically insert parenthesis and
> quotes as described in electric-pair-pairs.  Then, in 24.4, I borrowed
> code from my reasonably popular autopair.el extension and e-p-m became a
> mode that automatically infers what characters to pair from the syntax
> table of each mode.  Furthermore, in the new version, it also makes
> educated guesses about when to pair or when not to pair based, again on
> the information collected from the buffer and its syntax table by
> syntax-ppss.

I think that what is missing from this history is the stage where the
idea with proposed solution is first discussed on emacs-devel, where
conceptual problems can be identified and resolved.  As a result, e-p-m
is only compatible with some major modes; it is incompatible with those
that explicitly call self-insert-function as part of a command bound to
a key which is usually self-inserting.  There are quite a few such
modes.

> The use of post-self-insert-hook was a requirement at the time, since
> that is how the pre-24.4 electric-pair-mode, electric-indent-mode and
> electric-layout-mode already worked.  I welcomed this requirement, and
> it was what encouraged me to kill autopair.el and migrate to the new
> framework, since in autopair.el I had to rebind the parenthesis keys,
> which is akward (much like c-electric-brace and c-electric-paren are
> akward IMO).  This simplified the code tremendously.

Have a look at the doc string for self-insert-command, and ask yourself
what should happen on this call:

    (self-insert-command 1 &{)

.  The answer is, of course, that "{" should be inserted into the
buffer.  With electric-pair-mode-enabled, what actually happens is that
"{}" gets inserted instead.  This is broken.  I ask you to consider this
paragraph very carefully rather than reacting emotionally against it.
self-insert-command is broken, and this is the cause of the current bug.

What you seem to be suggesting is that rather than fix this breakage,
major modes like CC Mode (and there are quite a few) should have to work
around it.

> So these "well established conventions" are, with all due respect,
> nothing more than personal opinions based on a narrow experience with a
> subset of modes (maybe "mode" singular), tried and tested as it may be.

> If I abandon the post-self-insert-hook convention for e-p-m, I'll
> probably be breaking the e-p-m interaction with electric-indent-mode,
> electric-layout-mode, etc.  If there are existing problems with these
> interactions they should be fixed, but I will not fix e-p-m for
> interaction a specific part of cc-mode, unless you provide
> retro-compatible fix that guarantees existing behaviour outside cc-mode.

Again, you're much more familiar with electric-indent-mode, and friends.
Do they also break self-insert-command?

> I would rather declare e-p-m incompatible with that part of cc-mode and
> invest some time in providing alternatives based on
> electric-layout-mode, fixing Beatrix's problem by replacing bits of
> cc-mode-specific initialization in her init file with bits that works
> for all modes, including cc-mode.

You're trying to replace core CC Mode functionality.  Trying to do that
with a few quick hacks can only lead to frustration all round, and to
tears.

electric-layout-mode is incompatible with CC Mode.  This would have come
up in the discussion on emacs-devel and a resolution found if that
discussion had taken place.  Sadly it didn't, hence the incompatibility.
The same applies to electric-pair-mode.  We're having that discussion
now, sort of.

In CC Mode (and Cperl Mode, and Vera Mode,....), on insertion of a {,
the processing associated with the insertion needs to be allowed to
complete before the insertion of the mating }.  Above all,
self-insert-command needs to behave correctly, according to its
documentation.  It is surely not beyond us to fix these problems.

> João

-- 
Alan Mackenzie (Nuremberg, Germany).




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sat, 22 Dec 2018 12:41:02 GMT) Full text and rfc822 format available.

Message #65 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: João Távora <joaotavora <at> gmail.com>
Cc: Stefan Monnier <monnier <at> iro.umontreal.ca>, 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Sat, 22 Dec 2018 12:33:28 +0000
Hello, João.

On Sat, Dec 22, 2018 at 03:22:47 +0000, João Távora wrote:
> Alan Mackenzie <acm <at> muc.de> writes:

> > Hello, Beatrix.

> > As maintainer of CC Mode, I earnestly recommend you NOT to follow João's
> > suggestion.  It will not work, and will waste your time.

> What, exactly, will not work?

Can't say exactly, but a quick hack on some minor mode which violates
and attempts to duplicate the conventions of the major mode, not
intensively tested, is not going to work.

> > Even if it appears to work, you will end up picking out bugs for an
> > indeterminate period.

> What bugs?  If you know of any, it would be good to report them, right?

See above.

> > Basically, electric-pair-mode as it is currently built is incompatible
> > with CC Mode, as I have pointed out here, albeit somewhat
> > undiplomatically.

> > I suggest you do nothing until tempers amongst Emacs developers have
> > cooled down, and hopefully a genuine solution to the bug has been worked
> > out and implemented.

> If you don't like electric-layout-mode, don't use it.  I'm trying to
> develop an alternative to c-toggle-auto-newline ....

Which is the wrong thing to do.

> .... within the electric-*-mode frame.  It's an experiment which I
> don't even know if Stefan will agree to, but it seems to work.  If
> Beatrix wants to cooperate, why shouldn't she?

My reading of the situation is that Beatrix reported a bug,
expecting/hoping for it to be fixed, so that she can get on with her
work more effectively.  I don't think she wants to spend lots of time
debugging (which is our job).

> I'm not asking you to nuke c-toggle-auto-newline or anything, ....

It looks rather that we to me, I must say.

> .... but should we all be forced to use it?  I don't think it's
> sensible in a free software project, Alan (and my temper is quite cool
> when saying this :-))

Eh??  The auto-newline facility is there and is optional.  It is an
integral part of CC Mode.  Where is this "forcing" you're referring to?

I think the situation is that the various electric-... facilities can
only work with major modes designed in a particular restricted fashion -
they are not universal.  Your answer is to try and impose these
restrictions on all major modes.  That can't work, since we don't
control all such modes, and imposing restrictions is a Bad Thing
generally.

> Again, I said I don't have anything against making eletric-pair-mode
> compatible with c-toggle-auto-newline if someone comes up with a good
> solution that doesn't break e-p-m for other modes.  I will not invest
> time in looking into that solution, but you or someone else may, of
> course.

As I've said elsewhere, the key to the fix is fixing the breakage of
self-insert-command.  That is going to involve extensive changes to
electric-pair-mode, but will fix the problem rather than trying to work
around it.

My idea at the moment is to change from using post-self-insert-hook to
using post-command-hook, thus fixing self-insert-command.  There should
also be a buffer local variable holding the function to insert the
matching paren with, defaulting to self-insert-command, or similar.
Would this work, and if not, where would it fail?

Is there any documentation for the connections between
electric-pair-mode and the other electric-... facilities?

As I've also said elsewhere, the fundamental root of the current problem
is social: somebody inventing facilities which impose constraints on
Emacs in general, and imposing these on Emacs without public discussion.
That cannot end well, and it hasn't ended well.

> In the meantime let people explore alternatives, right?

It does not lie within my power to stop them.  ;-)

> João

-- 
Alan Mackenzie (Nuremberg, Germany).




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sat, 22 Dec 2018 13:48:01 GMT) Full text and rfc822 format available.

Message #68 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: João Távora <joaotavora <at> gmail.com>
To: Alan Mackenzie <acm <at> muc.de>
Cc: bea <at> klebe.blog, Stefan Monnier <monnier <at> IRO.UMontreal.CA>,
 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1;
 electric-pair-mode breaks auto-newline minor mode of cc-mode
Date: Sat, 22 Dec 2018 13:47:31 +0000
Hello Alan,

I will be, again, responding to your two emails in one.

Alan Mackenzie <acm <at> muc.de> writes:

> This clearly isn't true at the moment.  Have you tested it with, for
> example, Cperl Mode, or Vera Mode?  That characteristic is an
> aspiration, which is laudable.

Fair enough.  But what are the bugs in those modes?  I've just tested it
briefly there and it seems to work.  I type parenthesis of various kinds
and they get autopaired and autoskipped.

> I think that what is missing from this history is the stage where the
> idea with proposed solution is first discussed on emacs-devel, where
> conceptual problems can be identified and resolved.  As a result, e-p-m
> is only compatible with some major modes; it is incompatible with those
> that explicitly call self-insert-function as part of a command bound to
> a key which is usually self-inserting.  There are quite a few such
> modes.

I think, but I'm not sure, that anycommand that eventually calls
post-self-insert-hook would also work.

> The answer is, of course, that "{" should be inserted into the buffer.
> With electric-pair-mode-enabled, what actually happens is that "{}"
> gets inserted instead.  This is broken.  I ask you to consider this
> paragraph very carefully rather than reacting emotionally against it.

Alan, OK, that is your opinion, but please don't tell me which part of
my brain to use when reacting to something, that's a wee bit too
arrogant...

> Again, you're much more familiar with electric-indent-mode, and friends.
> Do they also break self-insert-command?

No idea.  And I'm not very familiar with them, no.

Look, the framework for inserting extra things in post-self-insert-hook
was already in place when I joined the party.  Be it space for indent or
newlines for layout or delimiters for pairing.  I just followed those
tracks, which apparently cause you dismay.  And I enjoyed it, hehehe,
sorry :-) it really did make coding easier.

> with a few quick hacks can only lead to frustration all round, and to
> tears.

My tears, certainly, because I'm such an emotional trainwreck :-)

> self-insert-command needs to behave correctly, according to its
> documentation.  It is surely not beyond us to fix these problems.

Of course there are different ways to solve problems.  I think the way I
am exploring is the best.  You think otherwise, that's OK.

> Can't say exactly, but a quick hack on some minor mode which violates
> and attempts to duplicate the conventions of the major mode, not
> intensively tested, is not going to work.

Who convened where to decide this that you call "convention"?

And exactly what conventions is electric-layout-mode breaking (btw, you
should be aware that electric-layout-mode exists since 2010: Again, long
before I joined the party).

>> What bugs?  If you know of any, it would be good to report them, right?
> See above.

I did, but I don't see any reports of flawed behaviour there.  I'm not
saying there aren't any bugs: I'm just saying you should first look to
indications or traces of these bugs before publically stating that there
are.

> Which is the wrong thing to do.

Did you see The Big Lebowsky by the Cohen brothers? :-) There's a nice
riposte there, apropos opinions.

> I don't think she wants to spend lots of time debugging (which is our
> job).

Yes, maybe.  It's up to her, of course.  But it's not my "job", it's
something I do for fun.  And Alan, I have some experience in dealing
with user's reports too (neatly over a decade long, since that seems to
matter to you) and some users are more cooperative than others, and
that's fine.

> Eh??  The auto-newline facility is there and is optional.  It is an
> integral part of CC Mode.  Where is this "forcing" you're referring
> to?

Fair enough, no "forcing".  It sounded like you were suggesting to
Beatrix that she stay away from any solution except yours, for no reason
other than your authority as CC-mode maintainer and some unsubstantiated
prophecies of disaster.

> Is there any documentation for the connections between
> electric-pair-mode and the other electric-... facilities?

I don't think so: unless you count comments.  The interfaces they adhere
to to work together is post-self-insert-hook, with a few hacks here and
there marked FIXME by Stefan.

> is social: somebody inventing facilities which impose constraints on
> Emacs in general, and imposing these on Emacs without public
> discussion.  That cannot end well, and it hasn't ended well.

There's something here that doesn't make sense: you repudiate
"constraints", but you laud "convention".  But, in my view, pieces of
software uses "interfaces" to work together.

We're just discussing here who violated them, that's all.

João

PS: Without public discussion??? This discussion _is_ public! :-)





Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sat, 22 Dec 2018 16:23:02 GMT) Full text and rfc822 format available.

Message #71 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> IRO.UMontreal.CA>
To: Alan Mackenzie <acm <at> muc.de>
Cc: bea <at> klebe.blog, João Távora <joaotavora <at> gmail.com>,
 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1;
 electric-pair-mode breaks auto-newline minor mode of cc-mode
Date: Sat, 22 Dec 2018 11:22:04 -0500
> I think I've worked out what I don't like about such (ab)use of
> post-self-insert-hook.

Great.  I'm not sure how it helps us fix the problem, tho.


        Stefan




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sat, 22 Dec 2018 16:36:02 GMT) Full text and rfc822 format available.

Message #74 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Beatrix Klebe <beeuhtricks <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: Alan Mackenzie <acm <at> muc.de>, bea <at> klebe.blog, 33794 <at> debbugs.gnu.org,
 João Távora <joaotavora <at> gmail.com>
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Sat, 22 Dec 2018 11:34:59 -0500
[Message part 1 (text/plain, inline)]
To clarify João, I make no judgment about the utility or morality of quick
hacks broadly. However, as someone who spends the majority of their time in
languages and systems which generally take a dim view of pervasive mutable
state, I am intensely wary of doing things to my configuration which risk
making it incompatible with future updates in dependent parts. Should this
problem ever be resolved more generally, it is quite possible I will not
hear about it, and your quick hack will start causing unexpected behavior
that I will then have to fix myself down the line. Indeed, I have oft mused
about creating an Emacslike programming environment in which packages are
pure and persistent and upgrades are done in a way that can be provably
reversed, like nix-pkgs does for system packages, purely because of my
historical frustration with things breaking when they shouldn’t and me not
being able to reliably isolate the cause of their failure.

On Sat, Dec 22, 2018 at 11:22 AM Stefan Monnier <monnier <at> iro.umontreal.ca>
wrote:

> > I think I've worked out what I don't like about such (ab)use of
> > post-self-insert-hook.
>
> Great.  I'm not sure how it helps us fix the problem, tho.
>
>
>         Stefan
>
[Message part 2 (text/html, inline)]

Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sat, 22 Dec 2018 17:13:02 GMT) Full text and rfc822 format available.

Message #77 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> IRO.UMontreal.CA>
To: Beatrix Klebe <beeuhtricks <at> gmail.com>
Cc: Alan Mackenzie <acm <at> muc.de>, bea <at> klebe.blog, 33794 <at> debbugs.gnu.org,
 João Távora <joaotavora <at> gmail.com>
Subject: Re: bug#33794: 26.1;
 electric-pair-mode breaks auto-newline minor mode of cc-mode
Date: Sat, 22 Dec 2018 12:12:33 -0500
> hear about it, and your quick hack will start causing unexpected behavior
> that I will then have to fix myself down the line. Indeed, I have oft mused

I believe there's a misunderstand here: his quick hack is intended to
figure out how to provide a long term solution.  IOW he's not proposing
it as a solution for you, but is rather asking you to help us write
a long term fix by testing design points.


        Stefan




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sat, 22 Dec 2018 17:35:02 GMT) Full text and rfc822 format available.

Message #80 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Beatrix Klebe <beeuhtricks <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: Alan Mackenzie <acm <at> muc.de>, bea <at> klebe.blog, 33794 <at> debbugs.gnu.org,
 João Távora <joaotavora <at> gmail.com>
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Sat, 22 Dec 2018 12:34:09 -0500
[Message part 1 (text/plain, inline)]
Well, in that case, I am flattered that my opinion is given much weight in
this. What I will say is that it seems like the first order of business is
to disambiguate what has which responsibilities in this case, and where the
line falls between major modes, electric-layout, and electric-pair. It
seems like this area of the electric modes is suffering from a bit of
fragmentation as well as differing perspectives on what constitutes
“electric” behavior. Things such as c-toggle-auto-newline, for example,
almost seem in this case that they might be better delegated to
electric-layout-mode, with cc-mode specifying different electric-layout
constraints for its different formatting styles. It seems this is close to
what João was suggesting? And I suspect what Alan disagrees with? I
apologize for any misunderstanding.

On Sat, Dec 22, 2018 at 12:12 PM Stefan Monnier <monnier <at> iro.umontreal.ca>
wrote:

> > hear about it, and your quick hack will start causing unexpected behavior
> > that I will then have to fix myself down the line. Indeed, I have oft
> mused
>
> I believe there's a misunderstand here: his quick hack is intended to
> figure out how to provide a long term solution.  IOW he's not proposing
> it as a solution for you, but is rather asking you to help us write
> a long term fix by testing design points.
>
>
>         Stefan
>
[Message part 2 (text/html, inline)]

Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sat, 22 Dec 2018 21:20:02 GMT) Full text and rfc822 format available.

Message #83 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: João Távora <joaotavora <at> gmail.com>
To: Beatrix Klebe <beeuhtricks <at> gmail.com>
Cc: Alan Mackenzie <acm <at> muc.de>, bea <at> klebe.blog,
 Stefan Monnier <monnier <at> iro.umontreal.ca>, 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1;
 electric-pair-mode breaks auto-newline minor mode of cc-mode
Date: Sat, 22 Dec 2018 21:19:22 +0000
Beatrix Klebe <beeuhtricks <at> gmail.com> writes:

> Well, in that case, I am flattered that my opinion is given much
> weight in this.

It's supposed to work like that everyday in the Emacs bug tracker.  If
it flatters you, so much the better :-)

> Things such as c-toggle-auto-newline, for example, almost seem in this
> case that they might be better delegated to electric-layout-mode, with
> cc-mode specifying different electric-layout constraints for its
> different formatting styles. It seems this is close to what João was
> suggesting?

Yes, that is precisely what I am suggesting.  I am happy that this point
made it across.

Though there is not any need to give up on c-toggle-auto-newline if you
don't use electric-pair-mode, or if you use some other tool like
smartparens, or perhaps even my older tool autopair.el (tho those tools
might have other drawbacks that I don't known)

> And I suspect what Alan disagrees with? I apologize for any
> misunderstanding.

Yes, Alan disagrees with this.  In his view, electric- modes are abusing
the semantics of post-self-insert-hook.  Well, at least in my view of
his views :-)

João

PS: I'm cleaning up the implementation of the more powerful
electric-layout mode in branch
scratch/fix-33794-extend-electric-layout-mode.  I'll let you know
if/when it is merged.




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sat, 22 Dec 2018 22:23:02 GMT) Full text and rfc822 format available.

Message #86 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: João Távora <joaotavora <at> gmail.com>,
 Beatrix Klebe <beeuhtricks <at> gmail.com>
Cc: bea <at> klebe.blog, Stefan Monnier <monnier <at> iro.umontreal.ca>,
 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Sat, 22 Dec 2018 22:15:40 +0000
Hello, Beatrix and João.

On Sat, Dec 22, 2018 at 21:19:22 +0000, João Távora wrote:
> Beatrix Klebe <beeuhtricks <at> gmail.com> writes:

> > Well, in that case, I am flattered that my opinion is given much
> > weight in this.

> It's supposed to work like that everyday in the Emacs bug tracker.  If
> it flatters you, so much the better :-)

> > Things such as c-toggle-auto-newline, for example, almost seem in this
> > case that they might be better delegated to electric-layout-mode, with
> > cc-mode specifying different electric-layout constraints for its
> > different formatting styles. It seems this is close to what João was
> > suggesting?

This is what I oppose.  Given how well CC Mode's auto-newline works,
such a change would almost certainly be a negative step in quality,
portability, and would be a lot of unrewarding work to do.  CC Mode
isn't broken, here.  It doesn't need fixing, here.

> Yes, that is precisely what I am suggesting.  I am happy that this point
> made it across.

> Though there is not any need to give up on c-toggle-auto-newline if you
> don't use electric-pair-mode, or if you use some other tool like
> smartparens, or perhaps even my older tool autopair.el (tho those tools
> might have other drawbacks that I don't known)

If electric-pair-mode was fixed, it would work perfectly well with CC
Mode.

> > And I suspect what Alan disagrees with? I apologize for any
> > misunderstanding.

One of the things, yes.  CC Mode has, for years, been under constant
attack from people who want to make Emacs major modes work only the way
they think modes should.  CC Mode works differently, for good reasons.
To adapt CC Mode the way these people want would have significant
disadvantages, including some lost functionality.

Right now, João's direction of travel seems to be to cement
electric-pair-mode's unusability in modes like CC Mode, of which there
are quite a few.  I hope I've misunderstood this and I'm mistaken.

> Yes, Alan disagrees with this.  In his view, electric- modes are abusing
> the semantics of post-self-insert-hook.  Well, at least in my view of
> his views :-)

Please don't misrepresent me like that.  The point is that the
electric-... modes abuse not so much the post-self-insert-hook (although
they do), but they totally break self-insert-command.  You have had
several hours to contest this, but by your silence appear to have
accepted it.

electric-pair-mode breaks self-insert-command.

self-insert-command is (or was) a general purpose command for inserting
typed characters into a buffer.  With electric-pair-mode enabled, it
ceases to be general purpose, being usable only in contexts blessed by
the electric-... functionality.  This is why CC Mode's auto-newline
broke.  It will stay broken until electric-pair-mode's breaking of that
function gets fixed.

> João

[ .... ]

-- 
Alan Mackenzie (Nuremberg, Germany).




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sat, 22 Dec 2018 22:56:02 GMT) Full text and rfc822 format available.

Message #89 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: João Távora <joaotavora <at> gmail.com>
To: Alan Mackenzie <acm <at> muc.de>
Cc: Beatrix Klebe <beeuhtricks <at> gmail.com>, bea <at> klebe.blog,
 Stefan Monnier <monnier <at> iro.umontreal.ca>, 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1;
 electric-pair-mode breaks auto-newline minor mode of cc-mode
Date: Sat, 22 Dec 2018 22:55:32 +0000
Alan Mackenzie <acm <at> muc.de> writes:

> Right now, João's direction of travel seems to be to cement
> electric-pair-mode's unusability in modes like CC Mode, of which there
> are quite a few.  I hope I've misunderstood this and I'm mistaken.

You are.  In fact, I'm coming up with alternatives so that
electric-pair-mode works with CC-Mode, even if the user or some other
mode customizes it to not use c-electric-{brace,paren}.

You may say that I am not working actively to make e-p-m work with
c-toggle-auto-newline, which *in my opinion* is a part of CC-mode that
could and should someday be fulfilled by electric-layout-mode.  That is
100% true.  But I am not preventing anyone from taking on that task, or
even suggesting it's trivial or very hard.  I just don't know, and I
have no interest in studying this alternative.

That is quite different from "cementing an unusability".Have a look at
my recent commits in scratch/fix-33794-extend-electric-layout-mode and
you will see that I have done 0 changes to e-p-m.

Also, can you once and for all describe the "unusabilities" in other
modes you keep talking about???

>> Yes, Alan disagrees with this.  In his view, electric- modes are abusing
>> the semantics of post-self-insert-hook.  Well, at least in my view of
>> his views :-)
>
> Please don't misrepresent me like that.

Really, I didn't.  But OK, I will think thrice before writing "Alan
thinks" sentences.

> The point is that the electric-... modes abuse not so much the
> post-self-insert-hook (although they do),

So, in reality I didn't misrepresent you.

> but they totally break self-insert-command.  You have had several
> hours to contest this, but by your silence appear to have accepted it.

How can I contest or accept that which I have no opinion of?  I'm not an
expert in the teleology of self-insert-command!  Find someone who is to
discuss this!

Frankly: "my silence"...  I'm not taking that bait, OK?  Really, Alan,
please please understand that I am only trying to make
electric-layout-mode work a bit better, and not even touching any of its
basic functioning vis-a-vis self-insert-command.

João







Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sun, 23 Dec 2018 14:44:02 GMT) Full text and rfc822 format available.

Message #92 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> IRO.UMontreal.CA>
To: Alan Mackenzie <acm <at> muc.de>
Cc: Beatrix Klebe <beeuhtricks <at> gmail.com>, bea <at> klebe.blog,
 João Távora <joaotavora <at> gmail.com>,
 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1;
 electric-pair-mode breaks auto-newline minor mode of cc-mode
Date: Sun, 23 Dec 2018 09:43:53 -0500
> Right now, João's direction of travel seems to be to cement
> electric-pair-mode's unusability in modes like CC Mode, of which there
> are quite a few.

Actually, there aren't many modes "like CC mode" in my experience.
But really, I don't see why you're complaining about João's attempt to
improve electric-layout-mode.  CC-mode doesn't even use that code, so
it's completely unaffected (at least until you decide to start using
electric-layout-mode).


        Stefan




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sun, 23 Dec 2018 14:49:01 GMT) Full text and rfc822 format available.

Message #95 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: bea <at> klebe.blog
Cc: 33794 <at> debbugs.gnu.org,
 João Távora <joaotavora <at> gmail.com>
Subject: Re: bug#33794: 26.1;
 electric-pair-mode breaks auto-newline minor mode of cc-mode
Date: 23 Dec 2018 14:48:37 -0000
Hello again, Beatrix.

In article <mailman.5894.1545155289.1284.bug-gnu-emacs <at> gnu.org> you wrote:
> When using cc-mode, turning on electric-pair-mode causes the
> auto-newline minor mode to stop inserting newlines where expected. This
> is relevant to the formatting of C# code with the Allman/BSD brace style
> in particular, though it would be nice if these modes specifically did
> work together.

> In GNU Emacs 26.1 (build 1, x86_64-apple-darwin14.5.0, NS
> appkit-1348.17 Version 10.10.5 (Build 14F2511))
>  of 2018-05-30 built on builder10-10.porkrind.org
> Windowing system distributor 'Apple', version 10.3.1671
> Recent messages:
> Saving file /Users/bea/.emacs.d/lisp/dotnet.el...
> Wrote /Users/bea/.emacs.d/lisp/dotnet.el
> ; expected
> Undo!
> ; expected
> Undo! [2 times]
> ; expected
> Auto-saving...
> ; expected [2 times]
> Making completion list...

I think the following workaround will give you a lot of what you want.
I've tried it out only on C Mode, however.  The pertinent file is in
.../emacs/lisp/progmodes/.

Sadly it is only a workaround, since there doesn't seem to be any
interface to electric-pair-mode usable by programs.  However, it should
help, whilst we at Emacs negotiate amongst ourselves.

Happy Christmas, if you celebrate it!  (And a good time, otherwise!).


diff -r 7ec0a318802a cc-cmds.el
--- a/cc-cmds.el	Thu Dec 20 12:07:55 2018 +0000
+++ b/cc-cmds.el	Sun Dec 23 14:34:51 2018 +0000
@@ -721,7 +721,9 @@
 
     ;; Insert the brace.  Note that expand-abbrev might reindent
     ;; the line here if there's a preceding "else" or something.
-    (self-insert-command (prefix-numeric-value arg))
+    (let (post-self-insert-hook) ; the only way to get dependable
+				 ; functionality from self-insert-command.
+      (self-insert-command (prefix-numeric-value arg)))
 
     (when (and c-electric-flag (not literal) (not arg))
       (if (not (looking-at "[ \t]*\\\\?$"))
@@ -844,6 +846,15 @@
 		(c-newline-and-indent))
 	    ))))
 
+    ;; Emulate `electric-pair-mode'.
+    (when (and (boundp 'electric-pair-mode)
+	       electric-pair-mode
+	       (eq last-command-event ?{))
+      (save-excursion
+	(newline)
+	(let ((last-command-event ?}))
+	  (c-electric-brace nil))))
+
     ;; blink the paren
     (and (eq (c-last-command-char) ?\})
 	 (not executing-kbd-macro)



-- 
Alan Mackenzie (Nuremberg, Germany).





Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sun, 23 Dec 2018 20:29:02 GMT) Full text and rfc822 format available.

Message #98 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: João Távora <joaotavora <at> gmail.com>
Cc: Beatrix Klebe <beeuhtricks <at> gmail.com>, bea <at> klebe.blog,
 Stefan Monnier <monnier <at> iro.umontreal.ca>, 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Sun, 23 Dec 2018 20:21:43 +0000
Hello, João.

On Sat, Dec 22, 2018 at 22:55:32 +0000, João Távora wrote:
> Alan Mackenzie <acm <at> muc.de> writes:

> > Right now, João's direction of travel seems to be to cement
> > electric-pair-mode's unusability in modes like CC Mode, of which there
> > are quite a few.  I hope I've misunderstood this and I'm mistaken.

> You are.  In fact, I'm coming up with alternatives so that
> electric-pair-mode works with CC-Mode, even if the user or some other
> mode customizes it to not use c-electric-{brace,paren}.

CC Mode is not customisable in this way, any more than any other major
mode.  Ripping out and replacing the innards of Lisp code is called
"hacking", not "customisation".

At the moment, electric-pair-mode does not work with c-electric-brace
and c-electric-paren.  This is the bug reported by Beatrix, the OP.  You
are telling me you are not working on fixing the part of this problem
which is in e-p-m.  Please understand me being somewhat frustrated by
this.  If I were to dig in to e-p-m, make fixes, and commit them, I
suspect you would be somewhat annoyed.

> You may say that I am not working actively to make e-p-m work with
> c-toggle-auto-newline, which *in my opinion* is a part of CC-mode that
> could and should someday be fulfilled by electric-layout-mode.

I think you really mean c-electric-{brace,paren} here, not
c-toggle-auto-newline.  electric-layout-mode won't be superseding those
functions any time soon.

> That is 100% true.  But I am not preventing anyone from taking on that
> task, or even suggesting it's trivial or very hard.  I just don't
> know, and I have no interest in studying this alternative.

But you're posting in the thread for bug #33794.  I'm disappointed
you're not cooperating with me to fix this bug.

> That is quite different from "cementing an unusability".Have a look at
> my recent commits in scratch/fix-33794-extend-electric-layout-mode and
> you will see that I have done 0 changes to e-p-m.

I'm not interested in that branch, I'm afraid.  electric-layout-mode has
no relevance to CC Mode.  I'm more interested in bug #33794.

> Also, can you once and for all describe the "unusabilities" in other
> modes you keep talking about???

Yes.  These other modes call self-insert-command.  self-insert-command,
because of the way post-self-insert-hook is (ab)used, has no definite
function.  Sometimes it does what the doc says (inserting N copies of
the last character typed), other times it does other things.

The only safe way for a mode to call self-insert-command is by binding
post-self-insert-hook to a known value, usually nil.  This prevents all
electric-pair-mode processing.

I would very much like c-electric-brace, etc., to be able to use e-p-m
functionality, rather than partially duplicating it inside cc-cmds.el,
as I did in the patch I sent to Beatrix, Cc: to yourself, earlier on
today.

> >> Yes, Alan disagrees with this.  In his view, electric- modes are
> >> abusing the semantics of post-self-insert-hook.  Well, at least in
> >> my view of his views :-)

> > Please don't misrepresent me like that.

> Really, I didn't.  But OK, I will think thrice before writing "Alan
> thinks" sentences.

Sorry, you didn't really, that's true.  But you did put the emphasis on
the wrong point.

> > The point is that the electric-... modes abuse not so much the
> > post-self-insert-hook (although they do),

> So, in reality I didn't misrepresent you.

> > but they totally break self-insert-command.  You have had several
> > hours to contest this, but by your silence appear to have accepted it.

> How can I contest or accept that which I have no opinion of?  I'm not an
> expert in the teleology of self-insert-command!  Find someone who is to
> discuss this!

You're working on #33794.  You must surely have some notion of the cause
of the bug.  I've said what my idea is, and I'm somewhat disappointed
you've failed to comment on this central point.  Without understanding
the cause of a bug, any fix is going to be suboptimal.

> Frankly: "my silence"...  I'm not taking that bait, OK?  Really, Alan,
> please please understand that I am only trying to make
> electric-layout-mode work a bit better, and not even touching any of its
> basic functioning vis-a-vis self-insert-command.

But you're commenting on this thread, which is about a bug concerning
the interaction of e-p-m with CC Mode, not e-l-m.

> João

-- 
Alan Mackenzie (Nuremberg, Germany).




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sun, 23 Dec 2018 21:39:01 GMT) Full text and rfc822 format available.

Message #101 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: João Távora <joaotavora <at> gmail.com>
To: Alan Mackenzie <acm <at> muc.de>
Cc: Beatrix Klebe <beeuhtricks <at> gmail.com>, bea <at> klebe.blog,
 Stefan Monnier <monnier <at> iro.umontreal.ca>, 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1;
 electric-pair-mode breaks auto-newline minor mode of cc-mode
Date: Sun, 23 Dec 2018 21:38:29 +0000
Hello Alan,

Alan Mackenzie <acm <at> muc.de> writes:

> Hello, João.

> CC Mode is not customisable in this way, any more than any other major
> mode.  Ripping out and replacing the innards of Lisp code is called
> "hacking", not "customisation".

Very well, if you consider my personal customization counts a hack, I
will just have to live with that weight on my shoulders.  I will not
report bugs about CC-mode based on my customization, only Emacs -Q.

Hmmm, come to think of it, I don't think I ever did.

> At the moment, electric-pair-mode does not work with c-electric-brace
> and c-electric-paren.  This is the bug reported by Beatrix, the OP.  You
> are telling me you are not working on fixing the part of this problem
> which is in e-p-m.  Please understand me being somewhat frustrated by
> this.  If I were to dig in to e-p-m, make fixes, and commit them, I
> suspect you would be somewhat annoyed.

If you propose changes to e-p-m that:

* don't break any (more) unit tests;

* don't introduce new interfaces to special case cc-mode;

* Stefan accepts, since the self-insert-command-hook part was his
  responsibility entirely, (as I have tried to explain a million times.)

Then I don't see why I would be annoyed.

(You could of course come to the faint realization that maybe there is
the off-chance that there exists a glimmer of possibility that in a
remote part of the multiverse it is quite possible that a minute part
the problem lies in cc-mode.  But no, that is preposterous! let us not
even consider that heresy!  It's decades old after all, it MUST be
correct, forever and absolutely!)

> But you're posting in the thread for bug #33794.  I'm disappointed
> you're not cooperating with me to fix this bug.

I'm posting here because you summoned me, remember?  And now I am
replying to you.  After analysing the problem of Beatrix, I offered an
alternative solution to her actual problem using electric-layout-mode.
(as have you in the meantime).  Seeing as electric-layout-mode was
manifestly insufficient to fix her problem I started working on making
it better.

>> Also, can you once and for all describe the "unusabilities" in other
>> modes you keep talking about???
> Yes.  These other modes call self-insert-command.  self-insert-command,
> because of the way post-self-insert-hook is (ab)used, has no definite
> function.  Sometimes it does what the doc says (inserting N copies of
> the last character typed), other times it does other things.

Again philosophical elucubrations?  Say one concrete thing that is
broken in these modes!  No far-fetched hypotheticals.  Here's a template
for your report:

   Emacs -Q
   M-x electric-pair-mode
   M-x horribly-broken-mode-that-only-you-know-about
   some legitimate user input
   some horribly wrong result

I'm not saying there aren't such bugs, but why are you evading the
question?  Or just say you haven't really witnessed any such bugs and
let's be done with the farce.

> You're working on #33794.  You must surely have some notion of the cause
> of the bug.  I've said what my idea is, and I'm somewhat disappointed
> you've failed to comment on this central point.  Without understanding
> the cause of a bug, any fix is going to be suboptimal.

Look, I haven't looked into this and I don't want to go into a
discussion with you about it because frankly, very frankly indeed, it
would be no fun.  You've already decided long ago that the world is
wrong.  Any comment I could make about how CC-mode could be changed
would just prompt some comment about how it's "always worked", "for
decades" and "look at how fluffy the whiskers on this gray old Gandalf
of a mode are", and "look at this young arriviste e-p-m rascal causing
all the mischief".  In a great part I symphatize immensely with your
ardent defense of your work, if it were literature or art I would
definitely be on your side, the patron saint of idiosyncrasies.  On the
other hand, seeing as this is software, I would find myself having to
point out that these arguments have no bearing on reality.

I'll say this: consider that it is not a bug: e-p-m's contract is: works
for every mode, except cc-mode, where mileage may vary.  Mileage is
indeed slightly shorter on cc-mode with c-toggle-auto-newline: let's
live with it and move on.

> But you're commenting on this thread, which is about a bug concerning
> the interaction of e-p-m with CC Mode, not e-l-m.

If you're suggesting I stop replying to these emails, then maybe you
have a point.  I'm a little tired.

Merry Christmas, Alan
João






Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Sun, 23 Dec 2018 21:53:02 GMT) Full text and rfc822 format available.

Message #104 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: João Távora <joaotavora <at> gmail.com>
Cc: Stefan Monnier <monnier <at> iro.umontreal.ca>, 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Sun, 23 Dec 2018 21:46:02 +0000
Hello, João.

On Sun, Dec 23, 2018 at 21:38:29 +0000, João Távora wrote:
> Hello Alan,

[ .... ]

> Merry Christmas, Alan

And a Merry Christmas to you too!  :-)

> João

-- 
Alan Mackenzie (Nuremberg, Germany).




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Fri, 28 Dec 2018 12:53:02 GMT) Full text and rfc822 format available.

Message #107 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: João Távora <joaotavora <at> gmail.com>
Cc: Beatrix Klebe <beeuhtricks <at> gmail.com>, bea <at> klebe.blog,
 Stefan Monnier <monnier <at> iro.umontreal.ca>, 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Fri, 28 Dec 2018 12:44:18 +0000
Hello, João.

On Sun, Dec 23, 2018 at 21:38:29 +0000, João Távora wrote:
> Alan Mackenzie <acm <at> muc.de> writes:

> > If I were to dig in to e-p-m, make fixes, and commit them, I suspect
> > you would be somewhat annoyed.

> If you propose changes to e-p-m that:

> * don't break any (more) unit tests;

> * don't introduce new interfaces to special case cc-mode;

> * Stefan accepts, since the self-insert-command-hook part was his
>   responsibility entirely, (as I have tried to explain a million times.)

> Then I don't see why I would be annoyed.

> (You could of course come to the faint realization that maybe there is
> the off-chance that there exists a glimmer of possibility that in a
> remote part of the multiverse it is quite possible that a minute part
> the problem lies in cc-mode.  But no, that is preposterous! let us not
> even consider that heresy!  It's decades old after all, it MUST be
> correct, forever and absolutely!)

The problem we're dealing with is in the interface between CC Mode and
electric-pair-mode.  Naturally, both sides of this putative interface
will need adapting.

From my point of view, what is missing from e-p-m is an interface usable
by functions which call self-insert-command programmatically, as CC Mode
does.  A function to insert the matching character and otherwise process
it.  Or something like that, I haven't fully worked it out.

Sadly, at the moment it's looking like the easiest way to fix bug #33794
would be to duplicate the functionality of electric-pair-mode inside CC
Mode, as I've already done partially.  I really don't want to do that,
and you probably don't want me to do that either.

[ .... ]

> João

-- 
Alan Mackenzie (Nuremberg, Germany).




Information forwarded to bug-gnu-emacs <at> gnu.org, bug-cc-mode <at> gnu.org:
bug#33794; Package emacs,cc-mode. (Tue, 01 Jan 2019 19:37:01 GMT) Full text and rfc822 format available.

Message #110 received at 33794 <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: bea <at> klebe.blog
Cc: 33794 <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Tue, 1 Jan 2019 19:27:29 +0000
Hello, Beatrix,

Happy New Year!

On Fri, Dec 21, 2018 at 11:00:10 -0500, Beatrix Klebe wrote:
> What would be ideal, and what I'm looking for, is to get auto-pairing
> of brackets with braces being placed where they should be
> automatically and the insertion point getting put in between them at
> the correct indent level, such as what happens with Visual Studio, or
> Visual Studio Code, or several other editors with this functionality.
> Perhaps it is not emacslike to have such behavior be totally
> automated, but I am used to it and finds it decreases my ordinary
> levels of frustration when working with verbose and imperative
> languages. I am currently trying to write some insert specifiers for
> smartparens to do this, but it is proving more difficult to find an
> elegant solution than I had expected.

I think the following patch to CC Mode gives you nearly everything you
want, if not actually everything.

It turned out that the amendment didn't require any modification to
electric-pair-mode, so apologies to João.

I don't know how much you've explored electric-pair-mode, but if the
answer is "not very much", can I suggest you try setting
electric-pair-skip-whitespace to 'chomp?  The following editing pattern
is then available.  With electric-pair-mode and c-auto-newline mode
enabled:

("|" represents point.)

At the end of the line

    if (foo)|
    foo = bar;

, type {.  This will give you something like:

    if (foo)
      {
        |
      }
    foo = bar;

.  Type in a statement ending with a semicolon:

    if (foo)
      {
        foo = bar;
	|
      }
    foo = bar;

.  Now type in }.  The effect is to "chomp" the space to the next }, and
CC Mode's auto-newline then inserts an empty line after the brace:

    if (foo)
      {
        foo = bar;
      }
    |
    foo = bar;

.  So, please try out the patch, and please let us all know how well it
corresponds with what you were looking for.  Also please let me know
about any bugs you notice, so that I can fix them.  Thanks for such an
interesting problem!

Here's the patch, which should apply cleanly to the emacs-26.1 source:



diff --git a/lisp/progmodes/cc-cmds.el b/lisp/progmodes/cc-cmds.el
index 65b44339bc..8038f29d3e 100644
--- a/lisp/progmodes/cc-cmds.el
+++ b/lisp/progmodes/cc-cmds.el
@@ -47,6 +47,7 @@
 ;; Silence the compiler.
 (cc-bytecomp-defvar filladapt-mode)	; c-fill-paragraph contains a kludge
 					; which looks at this.
+(cc-bytecomp-defun electric-pair-post-self-insert-function)
 
 ;; Indentation / Display syntax functions
 (defvar c-fix-backslashes t)
@@ -503,7 +504,8 @@ c-electric-pound
 			  (eq (char-before) ?\\))))
 	    (c-in-literal)))
       ;; do nothing special
-      (self-insert-command (prefix-numeric-value arg))
+      (let (post-self-insert-hook)	; Disable random functionality.
+	(self-insert-command (prefix-numeric-value arg)))
     ;; place the pound character at the left edge
     (let ((pos (- (point-max) (point)))
 	  (bolp (bolp)))
@@ -694,6 +696,134 @@ c-try-one-liner
 			    t))))
 	  (goto-char (- (point-max) pos))))))
 
+(defun c-do-brace-electrics (before after)
+  ;; Point is just after a brace.  Indent the various lines, add any required
+  ;; auto newlines, and apply pertinent clean ups.  It is assumed that the
+  ;; caller has checked that point is at EOL if need be, and that the brace is
+  ;; not in a comment or string, and suchlike.
+  ;;
+  ;; BEFORE and AFTER qualify the newlines required before and after the
+  ;; brace as follows:
+  ;; If
+  ;;  o - nil: insert a newline or not according to `c-hanging-braces-alist'.
+  ;;  o - 'ignore: don't insert a newline.
+  ;;  o - 'assume: insert a newline.
+  ;;
+  ;; The return value has no significance.
+  (let (;; shut this up too
+	(c-echo-syntactic-information-p nil)
+	newlines
+	ln-syntax br-syntax syntax)  ; Syntactic context of the original line,
+					; of the brace itself, of the line the
+					; brace ends up on.
+    (c-save-buffer-state ((c-syntactic-indentation-in-macros t)
+			  (c-auto-newline-analysis t))
+      (setq ln-syntax (c-guess-basic-syntax)))
+    (if c-syntactic-indentation
+	(c-indent-line ln-syntax))
+
+    (when c-auto-newline
+      (backward-char)
+      (setq br-syntax (c-point-syntax)
+	    newlines (c-brace-newlines br-syntax))
+
+      ;; Insert the BEFORE newline, if wanted, and reindent the newline.
+      (if (or (and (null before) (memq 'before newlines)
+		   (> (current-column) (current-indentation)))
+	      (eq before 'assume))
+	  (if c-syntactic-indentation
+	      ;; Only a plain newline for now - it's indented
+	      ;; after the cleanups when the line has its final
+	      ;; appearance.
+	      (newline)
+	    (c-newline-and-indent)))
+      (forward-char)
+
+      ;; `syntax' is the syntactic context of the line which ends up
+      ;; with the brace on it.
+      (setq syntax (if (memq 'before newlines) br-syntax ln-syntax))
+
+      ;; Do all appropriate clean ups
+      (let ((here (point))
+	    (pos (- (point-max) (point)))
+	    mbeg mend
+	    )
+
+	;; `}': clean up empty defun braces
+	(when (c-save-buffer-state ()
+		(and (memq 'empty-defun-braces c-cleanup-list)
+		     (eq (c-last-command-char) ?\})
+		     (c-intersect-lists '(defun-close class-close inline-close)
+					syntax)
+		     (progn
+		       (forward-char -1)
+		       (c-skip-ws-backward)
+		       (eq (char-before) ?\{))
+		     ;; make sure matching open brace isn't in a comment
+		     (not (c-in-literal))))
+	  (delete-region (point) (1- here))
+	  (setq here (- (point-max) pos)))
+	(goto-char here)
+
+	;; `}': compact to a one-liner defun?
+	(save-match-data
+	  (when
+	      (and (eq (c-last-command-char) ?\})
+		   (memq 'one-liner-defun c-cleanup-list)
+		   (c-intersect-lists '(defun-close) syntax)
+		   (c-try-one-liner))
+	    (setq here (- (point-max) pos))))
+
+	;; `{': clean up brace-else-brace and brace-elseif-brace
+	(when (eq (c-last-command-char) ?\{)
+	  (cond
+	   ((and (memq 'brace-else-brace c-cleanup-list)
+		 (re-search-backward
+		  (concat "}"
+			  "\\([ \t\n]\\|\\\\\n\\)*"
+			  "else"
+			  "\\([ \t\n]\\|\\\\\n\\)*"
+			  "{"
+			  "\\=")
+		  nil t))
+	    (delete-region (match-beginning 0) (match-end 0))
+	    (insert-and-inherit "} else {"))
+	   ((and (memq 'brace-elseif-brace c-cleanup-list)
+		 (progn
+		   (goto-char (1- here))
+		   (setq mend (point))
+		   (c-skip-ws-backward)
+		   (setq mbeg (point))
+		   (eq (char-before) ?\)))
+		 (zerop (c-save-buffer-state nil (c-backward-token-2 1 t)))
+		 (eq (char-after) ?\()
+		 (re-search-backward
+		  (concat "}"
+			  "\\([ \t\n]\\|\\\\\n\\)*"
+			  "else"
+			  "\\([ \t\n]\\|\\\\\n\\)+"
+			  "if"
+			  "\\([ \t\n]\\|\\\\\n\\)*"
+			  "\\=")
+		  nil t))
+	    (delete-region mbeg mend)
+	    (goto-char mbeg)
+	    (insert ?\ ))))
+
+	(goto-char (- (point-max) pos))
+
+	;; Indent the line after the cleanups since it might
+	;; very well indent differently due to them, e.g. if
+	;; c-indent-one-line-block is used together with the
+	;; one-liner-defun cleanup.
+	(when c-syntactic-indentation
+	  (c-indent-line)))
+
+      ;; does a newline go after the brace?
+      (if (or (and (null after) (memq 'after newlines))
+	      (eq after 'assume))
+	  (c-newline-and-indent)))))
+
 (defun c-electric-brace (arg)
   "Insert a brace.
 
@@ -716,7 +846,10 @@ c-electric-brace
 	;; We want to inhibit blinking the paren since this would be
 	;; most disruptive.  We'll blink it ourselves later on.
 	(old-blink-paren blink-paren-function)
-	blink-paren-function case-fold-search)
+	blink-paren-function case-fold-search
+	(at-eol (looking-at "[ \t]*\\\\?$"))
+	(active-region (and (fboundp 'use-region-p) (use-region-p)))
+	got-pair-} electric-pair-deletion)
 
     (c-save-buffer-state ()
       (setq safepos (c-safe-position (point) (c-parse-state))
@@ -724,128 +857,36 @@ c-electric-brace
 
     ;; Insert the brace.  Note that expand-abbrev might reindent
     ;; the line here if there's a preceding "else" or something.
-    (self-insert-command (prefix-numeric-value arg))
-
-    (when (and c-electric-flag (not literal) (not arg))
-      (if (not (looking-at "[ \t]*\\\\?$"))
-	  (if c-syntactic-indentation
-	      (indent-according-to-mode))
-
-	(let ( ;; shut this up too
-	      (c-echo-syntactic-information-p nil)
-	      newlines
-	      ln-syntax br-syntax syntax) ; Syntactic context of the original line,
-			; of the brace itself, of the line the brace ends up on.
-	  (c-save-buffer-state ((c-syntactic-indentation-in-macros t)
-				(c-auto-newline-analysis t))
-	    (setq ln-syntax (c-guess-basic-syntax)))
-	  (if c-syntactic-indentation
-	      (c-indent-line ln-syntax))
-
-	  (when c-auto-newline
-	    (backward-char)
-	    (setq br-syntax (c-point-syntax)
-		  newlines (c-brace-newlines br-syntax))
-
-	    ;; Insert the BEFORE newline, if wanted, and reindent the newline.
-	    (if (and (memq 'before newlines)
-		     (> (current-column) (current-indentation)))
-		(if c-syntactic-indentation
-		    ;; Only a plain newline for now - it's indented
-		    ;; after the cleanups when the line has its final
-		    ;; appearance.
-		    (newline)
-		  (c-newline-and-indent)))
+    (let (post-self-insert-hook) ; the only way to get defined functionality
+				 ; from `self-insert-command'.
+      (self-insert-command (prefix-numeric-value arg)))
+
+    ;; Emulate `electric-pair-mode'.
+    (when (and (boundp 'electric-pair-mode)
+	       electric-pair-mode)
+      (let ((size (buffer-size))
+	    (c-in-electric-pair-functionality t)
+	    post-self-insert-hook)
+	(electric-pair-post-self-insert-function)
+	(setq got-pair-} (and at-eol
+			      (eq (c-last-command-char) ?{)
+			      (eq (char-after) ?}))
+	      electric-pair-deletion (< (buffer-size) size))))
+
+    ;; Perform any required CC Mode electric actions.
+    (cond
+     ((or literal arg (not c-electric-flag) active-region))
+     ((not at-eol)
+      (c-indent-line))
+     (electric-pair-deletion
+      (c-indent-line)
+      (c-do-brace-electrics 'ignore nil))
+     (t (c-do-brace-electrics nil nil)
+	(when got-pair-}
+	  (save-excursion
 	    (forward-char)
-
-	    ;; `syntax' is the syntactic context of the line which ends up
-	    ;; with the brace on it.
-	    (setq syntax (if (memq 'before newlines) br-syntax ln-syntax))
-
-	    ;; Do all appropriate clean ups
-	    (let ((here (point))
-		  (pos (- (point-max) (point)))
-		  mbeg mend
-		  )
-
-	      ;; `}': clean up empty defun braces
-	      (when (c-save-buffer-state ()
-		      (and (memq 'empty-defun-braces c-cleanup-list)
-			   (eq (c-last-command-char) ?\})
-			   (c-intersect-lists '(defun-close class-close inline-close)
-					      syntax)
-			   (progn
-			     (forward-char -1)
-			     (c-skip-ws-backward)
-			     (eq (char-before) ?\{))
-			   ;; make sure matching open brace isn't in a comment
-			   (not (c-in-literal))))
-		(delete-region (point) (1- here))
-		(setq here (- (point-max) pos)))
-	      (goto-char here)
-
-	      ;; `}': compact to a one-liner defun?
-	      (save-match-data
-		(when
-		    (and (eq (c-last-command-char) ?\})
-			 (memq 'one-liner-defun c-cleanup-list)
-			 (c-intersect-lists '(defun-close) syntax)
-			 (c-try-one-liner))
-		  (setq here (- (point-max) pos))))
-
-	      ;; `{': clean up brace-else-brace and brace-elseif-brace
-	      (when (eq (c-last-command-char) ?\{)
-		(cond
-		 ((and (memq 'brace-else-brace c-cleanup-list)
-		       (re-search-backward
-			(concat "}"
-				"\\([ \t\n]\\|\\\\\n\\)*"
-				"else"
-				"\\([ \t\n]\\|\\\\\n\\)*"
-				"{"
-				"\\=")
-			nil t))
-		  (delete-region (match-beginning 0) (match-end 0))
-		  (insert-and-inherit "} else {"))
-		 ((and (memq 'brace-elseif-brace c-cleanup-list)
-		       (progn
-			 (goto-char (1- here))
-			 (setq mend (point))
-			 (c-skip-ws-backward)
-			 (setq mbeg (point))
-			 (eq (char-before) ?\)))
-		       (zerop (c-save-buffer-state nil (c-backward-token-2 1 t)))
-		       (eq (char-after) ?\()
-		      ; (progn
-			; (setq tmp (point))
-			 (re-search-backward
-			  (concat "}"
-				  "\\([ \t\n]\\|\\\\\n\\)*"
-				  "else"
-				  "\\([ \t\n]\\|\\\\\n\\)+"
-				  "if"
-				  "\\([ \t\n]\\|\\\\\n\\)*"
-				  "\\=")
-			  nil t);)
-		       ;(eq (match-end 0) tmp);
-			 )
-		  (delete-region mbeg mend)
-		  (goto-char mbeg)
-		  (insert ?\ ))))
-
-	      (goto-char (- (point-max) pos))
-
-	      ;; Indent the line after the cleanups since it might
-	      ;; very well indent differently due to them, e.g. if
-	      ;; c-indent-one-line-block is used together with the
-	      ;; one-liner-defun cleanup.
-	      (when c-syntactic-indentation
-		(c-indent-line)))
-
-	    ;; does a newline go after the brace?
-	    (if (memq 'after newlines)
-		(c-newline-and-indent))
-	    ))))
+	    (c-do-brace-electrics 'assume 'ignore))
+	  (c-indent-line))))
 
     ;; blink the paren
     (and (eq (c-last-command-char) ?\})
@@ -903,7 +944,8 @@ c-electric-slash
 		       c-electric-flag
 		       (eq (c-last-command-char) ?/)
 		       (eq (char-before) (if literal ?* ?/))))
-    (self-insert-command (prefix-numeric-value arg))
+    (let (post-self-insert-hook)	; Disable random functionality.
+      (self-insert-command (prefix-numeric-value arg)))
     (if indentp
 	(indent-according-to-mode))))
 
@@ -916,7 +958,8 @@ c-electric-star
 this indentation is inhibited."
 
   (interactive "*P")
-  (self-insert-command (prefix-numeric-value arg))
+  (let (post-self-insert-hook)		; Disable random functionality.
+    (self-insert-command (prefix-numeric-value arg)))
   ;; if we are in a literal, or if arg is given do not reindent the
   ;; current line, unless this star introduces a comment-only line.
   (if (c-save-buffer-state ()
@@ -963,7 +1006,8 @@ c-electric-semi&comma
       (setq lim (c-most-enclosing-brace (c-parse-state))
 	    literal (c-in-literal lim)))
 
-    (self-insert-command (prefix-numeric-value arg))
+    (let (post-self-insert-hook)	; Disable random functionality.
+      (self-insert-command (prefix-numeric-value arg)))
 
     (if (and c-electric-flag (not literal) (not arg))
 	;; do all cleanups and newline insertions if c-auto-newline is on.
@@ -1032,7 +1076,8 @@ c-electric-colon
 	 newlines is-scope-op
 	 ;; shut this up
 	 (c-echo-syntactic-information-p nil))
-    (self-insert-command (prefix-numeric-value arg))
+    (let (post-self-insert-hook)	; Disable random functionality.
+      (self-insert-command (prefix-numeric-value arg)))
     ;; Any electric action?
     (if (and c-electric-flag (not literal) (not arg))
 	;; Unless we're at EOL, only re-indentation happens.
@@ -1125,7 +1170,8 @@ c-electric-lt-gt
   (let ((c-echo-syntactic-information-p nil)
 	final-pos found-delim case-fold-search)
 
-    (self-insert-command (prefix-numeric-value arg))
+    (let (post-self-insert-hook)	; Disable random functionality.
+      (self-insert-command (prefix-numeric-value arg)))
     (setq final-pos (point))
 
 ;;;; 2010-01-31: There used to be code here to put a syntax-table text
@@ -1190,7 +1236,9 @@ c-electric-paren
 	;; shut this up
 	(c-echo-syntactic-information-p nil)
 	case-fold-search)
-    (self-insert-command (prefix-numeric-value arg))
+    (let (post-self-insert-hook) ; The only way to get defined functionality
+				 ; from `self-insert-command'.
+      (self-insert-command (prefix-numeric-value arg)))
 
     (if (and (not arg) (not literal))
 	(let* (	;; We want to inhibit blinking the paren since this will
@@ -1239,6 +1287,12 @@ c-electric-paren
 	      (delete-region (match-beginning 0) (match-end 0))
 	      (insert-and-inherit "} catch (")))
 
+	  ;; Apply `electric-pair-mode' stuff.
+	  (when (and (boundp 'electric-pair-mode)
+		     electric-pair-mode)
+	    (let (post-self-insert-hook)
+	      (electric-pair-post-self-insert-function)))
+
 	  ;; Check for clean-ups at function calls.  These two DON'T need
 	  ;; `c-electric-flag' or `c-syntactic-indentation' set.
 	  ;; Point is currently just after the inserted paren.



-- 
Alan Mackenzie (Nuremberg, Germany).




Reply sent to Alan Mackenzie <acm <at> muc.de>:
You have taken responsibility. (Tue, 15 Jan 2019 16:22:02 GMT) Full text and rfc822 format available.

Notification sent to bea <at> klebe.blog:
bug acknowledged by developer. (Tue, 15 Jan 2019 16:22:02 GMT) Full text and rfc822 format available.

Message #115 received at 33794-done <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: bea <at> klebe.blog
Cc: João Távora <joaotavora <at> gmail.com>,
 33794-done <at> debbugs.gnu.org
Subject: Re: bug#33794: 26.1; electric-pair-mode breaks auto-newline minor
 mode of cc-mode
Date: Tue, 15 Jan 2019 16:10:52 +0000
Hello, Beatrix.

I have committed the patch from two weeks ago (to the Emacs master
branch), and I'm closing the bug as fixed.

-- 
Alan Mackenzie (Nuremberg, Germany).



On Tue, Jan 01, 2019 at 19:27:29 +0000, Alan Mackenzie wrote:
> Hello, Beatrix,

> Happy New Year!

> On Fri, Dec 21, 2018 at 11:00:10 -0500, Beatrix Klebe wrote:
> > What would be ideal, and what I'm looking for, is to get auto-pairing
> > of brackets with braces being placed where they should be
> > automatically and the insertion point getting put in between them at
> > the correct indent level, such as what happens with Visual Studio, or
> > Visual Studio Code, or several other editors with this functionality.
> > Perhaps it is not emacslike to have such behavior be totally
> > automated, but I am used to it and finds it decreases my ordinary
> > levels of frustration when working with verbose and imperative
> > languages. I am currently trying to write some insert specifiers for
> > smartparens to do this, but it is proving more difficult to find an
> > elegant solution than I had expected.

> I think the following patch to CC Mode gives you nearly everything you
> want, if not actually everything.

> It turned out that the amendment didn't require any modification to
> electric-pair-mode, so apologies to João.

> I don't know how much you've explored electric-pair-mode, but if the
> answer is "not very much", can I suggest you try setting
> electric-pair-skip-whitespace to 'chomp?  The following editing pattern
> is then available.  With electric-pair-mode and c-auto-newline mode
> enabled:

> ("|" represents point.)

> At the end of the line

>     if (foo)|
>     foo = bar;

> , type {.  This will give you something like:

>     if (foo)
>       {
>         |
>       }
>     foo = bar;

> .  Type in a statement ending with a semicolon:

>     if (foo)
>       {
>         foo = bar;
> 	|
>       }
>     foo = bar;

> .  Now type in }.  The effect is to "chomp" the space to the next }, and
> CC Mode's auto-newline then inserts an empty line after the brace:

>     if (foo)
>       {
>         foo = bar;
>       }
>     |
>     foo = bar;

> .  So, please try out the patch, and please let us all know how well it
> corresponds with what you were looking for.  Also please let me know
> about any bugs you notice, so that I can fix them.  Thanks for such an
> interesting problem!

> Here's the patch, which should apply cleanly to the emacs-26.1 source:

[ snip patch ].




bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Wed, 13 Feb 2019 12:24:07 GMT) Full text and rfc822 format available.

This bug report was last modified 5 years and 85 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.