Dear AUCTeX developpers,

I enhanced left-right brace paring feature in AUCTeX, inspired from
YaTeX(http://www.yatex.org/).  Could you examine the attached patch?
I would appreciate if it is incorporated into AUCTeX.
The patch introduces the following 3 changes.
1. In LaTeX documents, current AUCTeX has special support for inserting
   \left macro when using TeX-insert-macro(C-c RET).  It asks left brace
   to use and supplies automatically \right macro and corresponding
   right brace as well as the intended \left macro and left brace.  I
   added the similar support to \bigl and its friends, too.
   Simple example key sequence: C-m RET bigl RET ( RET
   Be careful not to turn off the option TeX-arg-right-insert-p
   when trying this feature.
2. Please try enabling new customize option
   LaTeX-electric-left-right-brace.  If this option is on, just typing
   "(", "{" or "[" instantly adds the corresponding right brace ")", "}"
   or "]".  It also recognizes the preceeding backslash or size
   adjusting macros such as \left, \bigl etc., so the following
   completions will occur:
   "(" -> "()"
   "{" -> "{}"
   "[" -> "[]" (when typing single left brace)
   "\(" -> "\(\)"
   "\{" -> "\{\}"
   "\[" -> "\[\]" (when typing left brace just after backslash)
   "\left(" -> "\left(\right)"
   "\bigl[" ->"\bigl[\bigr]" (when typing just after \left or \bigl)
   "\Bigl\{" -> "\Bigl\{\Bigr\}" (just after \Bigl\)
   This feature may be a bit annoying when editing an already existing
   LaTeX document.  In that case, use "C-u 1" or "C-q" before typing
   "(", "{" or "[".  Then no completion is done and just a single left
   brace is inserted in the buffer.  In fact, with any non-nil prefix
   arguments, they behave in the same way as the normal
   self-insert-command.
3. When entering macros such as \langle, \lfloor and \lceil, which
   produce the left part of the paired braces, with C-c RET, they
   are treated similarly as the left braces "(", "{" and "[".
   For example, inserting \lfloor by C-c RET is immediately followed by
   the insertion of \rfloor.  And if the point locates just after \left
   or its friends, the correspoinding \right etc. will be supplied to
   \rfloor.
   Simple example key sequence: C-c RET lfloor RET
   Note that TeX-arg-right-insert-p should not be turned off for this
   case, too.
   As a side effect, when LaTeX-math-mode is on, just typing "`("
   inserts not only "\langle", but also "\rangle", at the point.

All the features described above honor the active region.  I.e., if
active region is present, the left-right brace pair will surround that
region.
As a result, C-c { is almost unnecessary when
LaTeX-electric-left-right-brace is enabled.  Just typing a "{" suffices
for that purpose.

I personally use amsmath quite often, so I enclosed a modification to
style/amsmath.el as well which fits with the above enhancements.  Thus
\lvert and \lVert are treated similarly with \lfloor etc. so that they
are paired with \rvert and \rVert respectively.

Best regards,
Ikumi Keita

P.S. I'm not on this list, so please include me on cc: when replying.

diff -r 3a047dee4c26 latex.el
--- a/latex.el	Thu Sep 19 16:39:42 2013 +0200
+++ b/latex.el	Tue Sep 24 04:12:56 2013 +0900
@@ -2173,6 +2173,11 @@
 The car of each entry is the brace used with \\left,
 the cdr is the brace used with \\right.")
 
+(defcustom LaTeX-electric-left-right-brace nil
+  "If non-nil, insert right brace with suitable macro after typing left brace."
+  :group 'LaTeX-macro
+  :type 'boolean)
+
 (defvar TeX-left-right-braces
   '(("[") ("]") ("\\{") ("\\}") ("(") (")") ("|") ("\\|")
     ("/") ("\\backslash") ("\\lfloor") ("\\rfloor")
@@ -2181,38 +2186,175 @@
     ("\\updownarrow") ("\\Updownarrow") ("."))
   "List of symbols which can follow the \\left or \\right command.")
 
+(defvar LaTeX-left-right-macros-association
+  '(("left" . "right")
+    ("bigl" . "bigr") ("Bigl" . "Bigr")
+    ("biggl" . "biggr") ("Biggl" . "Biggr"))
+  "Alist of macros for adjusting size of left and right braces.
+The car of each entry is for left brace and the cdr is for right brace.")
+
 (defun TeX-arg-insert-braces (optional &optional prompt)
   "Prompt for a brace for \\left and insert the corresponding \\right.
 If OPTIONAL is non-nil, insert the resulting value as an optional
 argument, otherwise as a mandatory one.  Use PROMPT as the prompt
 string."
-  (save-excursion
-    (backward-word 1)
-    (backward-char)
-    (LaTeX-newline)
-    (indent-according-to-mode)
-    (beginning-of-line 0)
-    (if (looking-at "^[ \t]*$")
-	(progn (delete-horizontal-space)
-	       (delete-char 1))))
-  (let ((left-brace (completing-read
-		     (TeX-argument-prompt optional prompt "Which brace")
-		     TeX-left-right-braces)))
-    (insert left-brace)
-    (LaTeX-newline)
+  (let (left-macro)
     (save-excursion
-      (let ((right-brace (cdr (assoc left-brace
-				     TeX-braces-association))))
-	(LaTeX-newline)
-	(insert TeX-esc "right")
-	(if (and TeX-arg-right-insert-p
-		 right-brace)
-	    (insert right-brace)
-	  (insert (completing-read
-		   (TeX-argument-prompt optional prompt "Which brace")
-		   TeX-left-right-braces)))
-	(indent-according-to-mode)))
-    (indent-according-to-mode)))
+      ;; Obtain macro name such as "left", "bigl" etc.
+      (setq left-macro (buffer-substring-no-properties
+                        (point)
+                        (progn (backward-word 1) (point))))
+      (backward-char)
+      (LaTeX-newline)
+      (indent-according-to-mode)
+      ;; Delete possibly produced blank line.
+      (beginning-of-line 0)
+      (if (looking-at "^[ \t]*$")
+          (progn (delete-horizontal-space)
+                 (delete-char 1))))
+    (let ((left-brace (completing-read
+                       (TeX-argument-prompt optional prompt
+					    "Which brace")
+                       TeX-left-right-braces)))
+      (insert left-brace)
+      (LaTeX-newline)
+      (indent-according-to-mode)
+      (save-excursion
+	(if (TeX-active-mark)
+	    (goto-char (mark)))
+        (LaTeX-newline)
+        (LaTeX-insert-corresponding-right-macro-and-brace
+         left-macro left-brace optional prompt)
+        (indent-according-to-mode)))))
+
+(defun TeX-arg-insert-right-brace-maybe (optional)
+  "Insert the suitable right brace macro such as \\rangle.
+Insertion is done when `TeX-arg-right-insert-p' is non-nil.
+If the left brace macro is preceeded by \\left, \\bigl etc.,
+supply the corresponding macro such as \\right before the right brace macro.
+OPTIONAL is ignored."
+  ;; Nothing is done when TeX-arg-right-insert-p is nil.
+  (when TeX-arg-right-insert-p
+    (let (left-brace left-macro)
+      (save-excursion
+	;; Obtain left brace macro name such as "\langle".
+	(setq left-brace (buffer-substring-no-properties
+			  (point)
+			  (progn (backward-word) (backward-char)
+				 (point)))
+	      ;; Obtain the name of preceeding left macro, if any,
+	      ;; such as "left", "bigl" etc.
+	      left-macro (LaTeX-find-preceeding-left-macro-name)))
+      (save-excursion
+	(if (TeX-active-mark)
+	    (goto-char (mark)))
+	(LaTeX-insert-corresponding-right-macro-and-brace
+	 left-macro left-brace optional)))))
+
+(defun LaTeX-insert-left-brace (arg)
+  "Insert typed left brace ARG times and possibly a correspondig right brace.
+Automatic right brace insertion is done only if no prefix ARG is given and
+`LaTeX-electric-left-right-brace' is non-nil.
+Normally bound to keys \(, { and [."
+  (interactive "*P")
+  (let ((auto-p (and LaTeX-electric-left-right-brace (not arg))))
+    (if (and auto-p
+	     (TeX-active-mark)
+	     (> (point) (mark)))
+	(exchange-point-and-mark))
+    (self-insert-command (prefix-numeric-value arg))
+    (if auto-p
+      (let ((lbrace (char-to-string last-command-event)) lmacro skip-p)
+        (save-excursion
+          (backward-char)
+	  ;; The brace "{" is exceptional in two aspects.
+	  ;; 1. "\{" should be considered as a single brace
+	  ;;    like "(" and "[".
+	  ;; 2. "\left{" is nonsense while "\left\{" and
+	  ;;    "\left(" are not.
+	  (if (string= lbrace TeX-grop)
+	      ;; If "{" follows "\", set lbrace to "\{".
+	      (if (TeX-escaped-p)
+		  (progn
+		    (backward-char)
+		    (setq lbrace (concat TeX-esc TeX-grop)))
+		;; Otherwise, don't search for left macros.
+		(setq skip-p t)))
+	  (unless skip-p
+	    ;; Obtain the name of preceeding left macro, if any,
+	    ;; such as "left", "bigl" etc.
+	    (setq lmacro (LaTeX-find-preceeding-left-macro-name))))
+        (let ((TeX-arg-right-insert-p t)
+              ;; "{" and "}" are paired temporally so that typing
+	      ;; a single "{" should insert a pair "{}".
+              (TeX-braces-association
+               (cons (cons TeX-grop TeX-grcl) TeX-braces-association)))
+	  (save-excursion
+	    (if (TeX-active-mark)
+		(goto-char (mark)))
+	    (LaTeX-insert-corresponding-right-macro-and-brace
+	     lmacro lbrace)))))))
+
+(defun LaTeX-insert-corresponding-right-macro-and-brace
+  (lmacro lbrace &optional optional prompt)
+  "Insert right macro and brace correspoinding to LMACRO and LBRACE.
+Left-right association is determined through
+`LaTeX-left-right-macros-association' and `TeX-braces-association'.
+
+If brace association can't be determined or `TeX-arg-right-insert-p'
+is nil, consult user which brace should be used."
+  ;; This function is called with LMACRO being one of the following
+  ;; possibilities.
+  ;;  (1) nil, which means LBRACE is isolated.
+  ;;  (2) null string, which means LBRACE follows right after "\" to
+  ;;      form "\(" or "\[".
+  ;;  (3) a string in CARs of `LaTeX-left-right-macros-association'.
+  (let ((rmacro (cdr (assoc lmacro LaTeX-left-right-macros-association)))
+	(rbrace (cdr (assoc lbrace TeX-braces-association))))
+    ;; Since braces like "\(" and "\)" should be paired, RMACRO
+    ;; should be considered as null string in the case (2).
+    (if (string= lmacro "")
+	(setq rmacro ""))
+    ;; Insert right macros such as "\right", "\bigr" etc., if necessary.
+    ;; Even single "\" will be inserted so that "\)" or "\]" is
+    ;; inserted after "\(", "\[".
+    (if rmacro
+	(insert TeX-esc rmacro))
+    (cond
+     ((and TeX-arg-right-insert-p rbrace)
+      (insert rbrace))
+     (rmacro
+      (insert (completing-read
+	       (TeX-argument-prompt
+		optional prompt
+		(format "Which brace (default %s)"
+			(or rbrace "."))) TeX-left-right-braces
+			nil nil nil nil (or rbrace ".")))))))
+
+(defun LaTeX-find-preceeding-left-macro-name ()
+  "Return the left macro name just before the point, if any.
+If the preceeding macro isn't left macros such as \\left, \\bigl etc.,
+return nil.
+If the point is just after unescaped `TeX-esc', return the null string."
+  ;; \left-!- => "left"
+  ;; \-!- => ""
+  ;; \infty-!- => nil
+  ;; \&-!- => nil
+  ;; \mathrm{abc}-!- => nil
+  ;; {blah blah blah}-!- => nil
+  ;; \\-!- => nil
+  (let ((name (buffer-substring-no-properties
+	       (point)
+	       ;; This is only a helper function, so we do not
+	       ;; preserve point by save-excursion.
+	       (progn
+		 ;; Assume left macro names consist of only A-Z and a-z.
+		 (skip-chars-backward "A-Za-z")
+		 (point)))))
+    (if (and (TeX-escaped-p)
+	     (or (string= name "")
+		 (assoc name LaTeX-left-right-macros-association)))
+	name)))
 
 (defcustom LaTeX-default-author 'user-full-name
   "Initial input to `LaTeX-arg-author' prompt.
@@ -4858,6 +5000,9 @@
     (define-key map "\C-c~"    'LaTeX-math-mode) ;*** Dubious
 
     (define-key map "-" 'LaTeX-babel-insert-hyphen)
+    (define-key map "(" 'LaTeX-insert-left-brace)
+    (define-key map "{" 'LaTeX-insert-left-brace)
+    (define-key map "[" 'LaTeX-insert-left-brace)
     map)
   "Keymap used in `LaTeX-mode'.")
 
@@ -5647,6 +5792,15 @@
    '("caption" t)
    '("marginpar" [ "Left margin text" ] "Text")
    '("left" TeX-arg-insert-braces)
+   ;; The following 4 macros are not specific to amsmath.
+   '("bigl" TeX-arg-insert-braces)
+   '("Bigl" TeX-arg-insert-braces)
+   '("biggl" TeX-arg-insert-braces)
+   '("Biggl" TeX-arg-insert-braces)
+
+   '("langle" TeX-arg-insert-right-brace-maybe)
+   '("lceil" TeX-arg-insert-right-brace-maybe)
+   '("lfloor" TeX-arg-insert-right-brace-maybe)
 
    ;; These have no special support, but are included in case the
    ;; auto files are missing.
diff -r 3a047dee4c26 style/amsmath.el
--- a/style/amsmath.el	Thu Sep 19 16:39:42 2013 +0200
+++ b/style/amsmath.el	Tue Sep 24 04:12:56 2013 +0900
@@ -94,7 +94,9 @@
      '("ddddot" t)
      "bmod" "notag"
      "dots" "dotsb" "dotsc" "dotsi" "dotsm" "dotso" "nobreakdash" 
-     "lvert" "rvert" "lVert" "rVert" 
+     '("lvert" TeX-arg-insert-right-brace-maybe)
+     '("lVert" TeX-arg-insert-right-brace-maybe)
+     "rvert" "rVert"
      "iint" "iiint" "iiiint" "idotsint"
      )
     
@@ -139,6 +141,14 @@
 		    ("gather"     . LaTeX-amsmath-label))
 		  LaTeX-label-alist))
 
+    (set (make-local-variable 'TeX-braces-association)
+	 (append '(("\\lvert" . "\\rvert")
+		   ("\\lVert" . "\\rVert"))
+		 TeX-braces-association))
+    (set (make-local-variable 'TeX-left-right-braces)
+	 (append '(("\\lvert") ("\\rvert") ("\\lVert") ("\\rVert"))
+		 TeX-left-right-braces))
+
     ;; amsmath includes amstext, amsbsy, & amsopn.
     ;; So we run their hooks, too.
     (TeX-run-style-hooks "amstext" "amsbsy" "amsopn")
_______________________________________________
auctex-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/auctex-devel

Reply via email to