Hi all,

The next thing I'd like to discuss is scope environment in TikZ. 

The scope environment is practically always accompanied by an optional
argument by its nature:
\begin{tikzpicture}
  \begin{scope}[TikZ options...]
  ...
  \end{scope}
\end{tikzpicture}
In other words, its "optional" argument is virtually a kind of mandatory
argument.

So I'm thinking to apply the attached patch. It modifies the AUCTeX
behavior with respect to the scope environment to insert a bracket pair
"[]" even when the user gave empty answer for query of optional
argument. In addition, it moves the point inside in that empty "[]",
assuming that the user actually expects to fill in that bracket
immediately, possibly with the help of in-buffer completion facility.

I admit that it might be a bit too aggresive. What do you think about
this idea?

Best,
Ikumi Keita
#StandWithUkraine #StopWarInUkraine

diff --git a/context.el b/context.el
index 40eacda8..6b99531d 100644
--- a/context.el
+++ b/context.el
@@ -759,40 +759,133 @@ With optional ARG, modify current environment."
   (end-of-line)
   (newline))
 
+(defvar ConTeXt-after-insert-env-hook nil
+  "List of functions to be run at the end of `ConTeXt-insert-environment'.
+Each function is called with three arguments: the name of the
+environment just inserted, the buffer position just before
+\\start... and the position just before \\stop....")
+
+;;; Copy and adaptation of `LaTeX-insert-environment'.  (2022-08-13)
 (defun ConTeXt-insert-environment (environment &optional extra)
-  "Insert ENVIRONMENT, with optional argument EXTRA."
-  (if (and (TeX-active-mark)
-           (not (eq (mark) (point))))
+  "Insert ConTeXt ENVIRONMENT with optional argument EXTRA."
+  (let ((active-mark (and (TeX-active-mark) (not (eq (mark) (point)))))
+        content-start env-start env-end additional-indent)
+    (when (and active-mark (< (mark) (point))) (exchange-point-and-mark))
+    ;; What to do with the line containing point.
+    ;; - Open a new empty line for later insertion of "\startfoo" and
+    ;;   put the point there.
+    ;; - If there were at first any non-whitespace texts between the
+    ;;   point and EOL, send them into their new own line.
+    (cond (;; When the entire line consists of whitespaces...
+           (save-excursion (beginning-of-line)
+                           (looking-at "[ \t]*$"))
+           ;; ...make the line empty and put the point there.
+           (delete-region (match-beginning 0) (match-end 0)))
+          (;; When there are only whitespaces between the point and
+           ;; BOL (including the case the point is at BOL)...
+           (TeX-looking-at-backward "^[ \t]*"
+                                    (line-beginning-position))
+           ;; ...in this case, we have non-whitespace texts between
+           ;; the point and EOL, so send the entire line into a new
+           ;; next line and put the point on the empty line just
+           ;; created.
+           (beginning-of-line)
+           (newline)
+           (beginning-of-line 0)
+           ;; Take note that there are texts to be indented later
+           ;; unless the region is activated.
+           (unless active-mark
+             (setq additional-indent t)))
+          (;; In all other cases...
+           t
+           ;; ...insert a new empty line after deleting all
+           ;; whitespaces around the point, put the point there...
+           (delete-horizontal-space)
+           (if (eolp)
+               (newline)
+             ;; ...and if there were at first any non-whitespace texts
+             ;; between (the original position of) the point and EOL,
+             ;; send them into a new next line.
+             (newline 2)
+             (beginning-of-line 0)
+             ;; Take note that there are texts to be indented later
+             ;; unless the region is activated.
+             (unless active-mark
+               (setq additional-indent t)))))
+    ;; What to do with the line containing mark.
+    ;; If there is active region...
+    (when active-mark
+      ;; - Open a new empty line for later insertion of "\stopfoo"
+      ;;   and put the mark there.
+      ;; - If there were at first any non-whitespace texts between the
+      ;;   mark and EOL, pass them over the empty line and put them on
+      ;;   their own line.
       (save-excursion
-        (if (< (mark) (point))
-            (exchange-point-and-mark))
-        (insert TeX-esc (ConTeXt-environment-start-name) environment)
-        (newline)
-        (forward-line -1)
-        (indent-according-to-mode)
-        (if extra (insert extra))
         (goto-char (mark))
-        (or (TeX-looking-at-backward "^[ \t]*")
-            (newline))
-        (insert TeX-esc (ConTeXt-environment-stop-name) environment)
-        (newline)
-        (forward-line -1)
-        (indent-according-to-mode)
-        ;;(goto-char (point))
-        )
-    (or (TeX-looking-at-backward "^[ \t]*")
-        (newline))
+        (cond (;; When the entire line consists of whitespaces...
+               (save-excursion (beginning-of-line)
+                               (looking-at "[ \t]*$"))
+               ;; ...make the line empty and put the mark there.
+               (delete-region (match-beginning 0) (match-end 0)))
+              (;; When there are only whitespaces between the mark and
+               ;; BOL (including the case the mark is at BOL)...
+               (TeX-looking-at-backward "^[ \t]*"
+                                        (line-beginning-position))
+               ;; ...in this case, we have non-whitespace texts
+               ;; between the mark and EOL, so send the entire line
+               ;; into a new next line and put the mark on the empty
+               ;; line just created.
+               (beginning-of-line)
+               (set-mark (point))
+               (newline)
+               ;; Take note that there are texts to be indented later.
+               (setq additional-indent t))
+              (;; In all other cases...
+               t
+               ;; ...make a new empty line after deleting all
+               ;; whitespaces around the mark, put the mark there...
+               (delete-horizontal-space)
+               (insert-before-markers "\n")
+               ;; ...and if there were at first any non-whitespace
+               ;; texts between (the original position of) the mark
+               ;; and EOL, send them into a new next line.
+               (unless (eolp)
+                 (newline)
+                 ;; Take note that there are texts to be indented
+                 ;; later.
+                 (setq additional-indent t))))))
+    ;; Now insert the environment.
+    (setq env-start (point))
     (insert TeX-esc (ConTeXt-environment-start-name) environment)
     (indent-according-to-mode)
-    (if extra (insert extra))
-    (end-of-line)
-    (newline-and-indent)
-    (newline)
+    (when extra (insert extra))
+    (setq content-start (line-beginning-position 2))
+    (unless active-mark
+      (newline)
+      (newline))
+    (when active-mark (goto-char (mark)))
     (insert TeX-esc (ConTeXt-environment-stop-name) environment)
-    (or (looking-at "[ \t]*$")
-        (save-excursion (newline-and-indent)))
-    (indent-according-to-mode)
-    (end-of-line 0)))
+    (end-of-line 0)
+    (if active-mark
+        (progn
+          ;; TODO: Do filling when context.el obtains
+          ;; `ConTeXt-fill-region' in future.
+          (indent-region content-start (line-beginning-position 2))
+          (set-mark content-start))
+      (indent-according-to-mode))
+    ;; Indent \stopfoo.
+    (save-excursion (beginning-of-line 2) (indent-according-to-mode)
+                    (when additional-indent
+                      ;; Indent texts sent after the inserted
+                      ;; environment.
+                      (forward-line 1) (indent-according-to-mode)))
+    (setq env-end (save-excursion
+                    (search-forward
+                     (concat TeX-esc (ConTeXt-environment-stop-name)
+                             environment))
+                    (match-beginning 0)))
+    (run-hook-with-args 'ConTeXt-after-insert-env-hook
+                        environment env-start env-end)))
 
 
 ;; with the following we can call a function on an environment. Say
diff --git a/style/tikz.el b/style/tikz.el
index a0edfd46..34322fd2 100644
--- a/style/tikz.el
+++ b/style/tikz.el
@@ -36,6 +36,8 @@
 ;; Silence compiler
 (declare-function ConTeXt-add-environments "context"
                   (&rest environments))
+(declare-function ConTeXt-insert-environment "context"
+                  (environment &optional extra))
 
 (defgroup AUCTeX-TikZ nil
   "AUCTeX TikZ support"
@@ -85,8 +87,8 @@
 (defun TeX-TikZ-get-opt-arg-string (arg &optional open close)
   "Return a string for optional arguments.
 If ARG is nil or \"\", return \"\".  Otherwise return \"OPEN ARG
-CLOSE\". If OPEN or CLOSE are nil, set them to `LaTeX-optop' and
-`LaTeX-optcl' respectively."
+CLOSE\".  If OPEN and CLOSE are nil, set them to `LaTeX-optop'
+and `LaTeX-optcl' respectively."
   (unless (or open close)
     (setq open LaTeX-optop)
     (setq close LaTeX-optcl))
@@ -284,6 +286,25 @@ return \"\"."
         (label (TeX-TikZ-arg-label nil)))
     (insert options " " name  " at" point label ";")))
 
+;; TODO: Add similar support for plain TeX.
+(defun TeX-TikZ-env-scope (environment)
+  "Insert scope ENVIRONMENT.
+Ask the user for TikZ option and insert it with surrounding \"[]\".
+If the user provides empty input, insert \"[]\" anyway and put the
+point inside it."
+  (let ((active-mark (and (TeX-active-mark) (not (eq (mark) (point)))))
+        (option (TeX-TikZ-arg-options nil)))
+    (cond
+     ((eq TeX-style-hook-dialect :latex)
+      (LaTeX-insert-environment environment option))
+     ((eq TeX-style-hook-dialect :context)
+      (ConTeXt-insert-environment environment option)))
+    (when (string= option "[]")
+      (if active-mark
+          (goto-char (mark)))
+      (end-of-line 0)
+      (backward-char 1))))
+
 (TeX-add-style-hook
  "tikz"
  (lambda ()
@@ -311,7 +332,7 @@ return \"\"."
  (lambda ()
    (LaTeX-add-environments
     '("tikzpicture" ["TikZ option"])
-    '("scope" ["TikZ option"]))
+    '("scope" TeX-TikZ-env-scope))
    ;; tikz.sty loads pgfcore.sty, which loads packages graphicx,
    ;; keyval and xcolor, too.
    (TeX-run-style-hooks "pgf" "graphicx" "keyval" "xcolor"))
@@ -323,7 +344,7 @@ return \"\"."
  (lambda ()
    (ConTeXt-add-environments
     '("tikzpicture" ["TikZ option"])
-    '("scope" ["TikZ option"])))
+    '("scope" TeX-TikZ-env-scope)))
  :context)
 
 ;; plain TeX specific stuff

Reply via email to