all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Stephen Meister <pallagun@gmail.com>
To: 7937@debbugs.gnu.org
Subject: bug#7937: nxml-mode indenting bug fix.
Date: Tue, 28 Mar 2023 15:05:05 -0400	[thread overview]
Message-ID: <CAMrh0GMapEMPaeR=y=qYu8MHXpA5DhsSejcWXLMeWB4e_f26CA@mail.gmail.com> (raw)
In-Reply-To: <87tygr9ych.fsf@jidanni.org>


[-- Attachment #1.1: Type: text/plain, Size: 752 bytes --]

Hi,
  I've tried to put a fix in place for bug 7937 (and possibly 7768
unintentionally).  The repair I've made will cause changes in the way that
nxml indents lines under normal circumstances.  I'm not sure if a change
like this is acceptable given that I'm only trying to fix a bug.  The
behavior change is most visible in a situation such as:

<root>
  <a><b><c>
    inner
  </c>
</b>
  </a>
</root>

Which would now be indented as:
<root>
  <a><b><c>
        inner
      </c>
    </b>
  </a>
</root>

There are additional tests which show more of the indenting changes as well.

This is my first bug fix, please let me know if I've missed anything
(procedurally or otherwise).  I'm happy to rework/restructure this based on
any suggestions.

-steve

[-- Attachment #1.2: Type: text/html, Size: 1134 bytes --]

[-- Attachment #2: bug7937.patch --]
[-- Type: text/x-patch, Size: 8619 bytes --]

diff --git a/lisp/nxml/nxml-mode.el b/lisp/nxml/nxml-mode.el
index 3869d0327fd..74108fa9d73 100644
--- a/lisp/nxml/nxml-mode.el
+++ b/lisp/nxml/nxml-mode.el
@@ -1327,7 +1327,8 @@ nxml-compute-indent-from-matching-start-tag
 its line.  Otherwise return nil."
   (save-excursion
     (back-to-indentation)
-    (let ((bol (point)))
+    (let ((bol (point))
+          bol-token-type)
       (let ((inhibit-field-text-motion t))
 	(end-of-line))
       (skip-chars-backward " \t")
@@ -1338,6 +1339,7 @@ nxml-compute-indent-from-matching-start-tag
 	       (save-excursion
 		 (goto-char bol)
 		 (nxml-token-after)
+                 (setq bol-token-type xmltok-type)
 		 (= xmltok-start bol))
 	       (eq xmltok-type 'data))
 	   (condition-case nil
@@ -1352,15 +1354,19 @@ nxml-compute-indent-from-matching-start-tag
 	     (goto-char xmltok-start)
 	     (skip-chars-backward " \t")
 	     (bolp))
-	   (current-indentation)))))
+	   (+ (current-indentation)
+              ;; in the case of a line starting with data, keep the
+              ;; indent level above the starting tag.
+              (if (eq bol-token-type 'data)
+                  nxml-child-indent
+                0))))))
 
 (defun nxml-compute-indent-from-previous-line ()
   "Compute the indent for a line using the indentation of a previous line."
   (save-excursion
     (end-of-line)
     (let ((eol (point))
-	  bol prev-bol ref
-	  before-context after-context)
+	  bol prev-bol ref)
       (back-to-indentation)
       (setq bol (point))
       (catch 'indent
@@ -1378,60 +1384,48 @@ nxml-compute-indent-from-previous-line
 		   (not (or (= xmltok-start (point))
 			    (eq xmltok-type 'data))))))
 	(setq ref (point))
-	;; Now scan over tokens until the end of the line to be indented.
-	;; Determine the context before and after the beginning of the
-	;; line.
-	(while (< (point) eol)
-	  (nxml-tokenize-forward)
-	  (cond ((<= bol xmltok-start)
-		 (setq after-context
-		       (nxml-merge-indent-context-type after-context)))
-		((and (<= (point) bol)
-		      (not (and (eq xmltok-type 'partial-start-tag)
-				(= (point) bol))))
-		 (setq before-context
-		       (nxml-merge-indent-context-type before-context)))
-		((eq xmltok-type 'data)
-		 (setq before-context
-		       (nxml-merge-indent-context-type before-context))
-		 (setq after-context
-		       (nxml-merge-indent-context-type after-context)))
-		;; If in the middle of a token that looks inline,
-		;; then indent relative to the previous non-blank line
-		((eq (nxml-merge-indent-context-type before-context)
-		     'mixed)
-		 (goto-char prev-bol)
-		 (throw 'indent (current-column)))
-		(t
-		 (throw 'indent
-			(nxml-compute-indent-in-token bol))))
-	  (skip-chars-forward " \t\r\n"))
-	(goto-char ref)
-	(+ (current-column)
-	   (* nxml-child-indent
-	      (+ (if (eq before-context 'start-tag) 1 0)
-		 (if (eq after-context 'end-tag) -1 0))))))))
-
-(defun nxml-merge-indent-context-type (context)
-  "Merge the indent context type CONTEXT with the token in `xmltok-type'.
-Return the merged indent context type.  An indent context type is
-either nil or one of the symbols `start-tag', `end-tag', `markup',
-`comment', `mixed'."
-  (cond ((memq xmltok-type '(start-tag partial-start-tag))
-	 (if (memq context '(nil start-tag comment))
-	     'start-tag
-	   'mixed))
-	((memq xmltok-type '(end-tag partial-end-tag))
-	 (if (memq context '(nil end-tag comment))
-	     'end-tag
-	   'mixed))
-	((eq xmltok-type 'comment)
-	 (cond ((memq context '(start-tag end-tag comment))
-		context)
-	       (context 'mixed)
-	       (t 'comment)))
-	(context 'mixed)
-	(t 'markup)))
+        (let ((depth-before 0)
+              (depth-after 0)
+              start-type-before)
+          (nxml-tokenize-forward)
+          (when (> (point) bol)         ; one token spans this and the line before
+            (throw 'indent (nxml-compute-indent-in-token bol)))
+          
+          ;; Scan over the prevous line to determine the change in element depth
+          (setq start-type-before xmltok-type)
+          (while (< (point) bol)        ; examine all tags on the previous line
+            (cond ((eq xmltok-type 'partial-start-tag)
+                   (throw 'indent (nxml-compute-indent-in-token bol)))
+                  ((eq xmltok-type 'start-tag)
+                   (cl-incf depth-before))
+                  ((eq xmltok-type 'end-tag)
+                   (cl-incf depth-before -1)))
+            (skip-chars-forward " \t\r\n")
+            (nxml-tokenize-forward))
+          
+          ;; Scan over the current line to determine the change in element depth
+          (while (and (<= (point) eol)        ; examine all tags on the current line.
+                      (< (point) (point-max)))
+            (cond ((eq  xmltok-type 'start-tag)
+                   (cl-incf depth-after))
+                  ((eq xmltok-type 'end-tag)
+                   (cl-incf depth-after -1)))
+            (skip-chars-forward " \t\r\n")
+            (nxml-tokenize-forward))
+          
+          (goto-char ref)
+	  (+ (current-column)
+	     (* nxml-child-indent
+                (+ (max 0 depth-before)
+                   (min 0 depth-after)
+                   ;; if our before-line started as a data element we
+                   ;; must back out that indentation as well as long
+                   ;; as we are not beginning additional tags
+                   (if (and (memq start-type-before '(data cdata-section))
+                            (>= depth-after 0)
+                            (< depth-before 0))
+                       -1
+                     0)))))))))
 
 (defun nxml-compute-indent-in-token (pos)
   "Return the indent for a line that starts inside a token.
diff --git a/test/lisp/nxml/nxml-mode-tests.el b/test/lisp/nxml/nxml-mode-tests.el
index 973f2ebb67e..532c39e8608 100644
--- a/test/lisp/nxml/nxml-mode-tests.el
+++ b/test/lisp/nxml/nxml-mode-tests.el
@@ -31,6 +31,17 @@ nxml-mode-tests-correctly-indented-string
 
 (ert-deftest nxml-indent-line-after-attribute ()
   (should (nxml-mode-tests-correctly-indented-string "
+<settings xmlns=\"http://maven.apache.org/SETTINGS/1.0.0\"
+          xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
+          xsi:schemaLocation=\"http://maven.apache.org/SETTINGS/1.0.0
+                              https://maven.apache.org/xsd/settings-1.0.0.xsd\">
+  <mirrors one=\"two\"
+           three=\"four\">
+    ...
+  </mirrors>
+</settings>
+"))
+  (should (nxml-mode-tests-correctly-indented-string "
 <settings
     xmlns=\"http://maven.apache.org/SETTINGS/1.0.0\"
     xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
@@ -155,5 +166,100 @@ nxml-mode-test-comment-bug-17264
       ;; Inside comment
       (should (eq (nth 4 (syntax-ppss)) t)))))
 
+(ert-deftest nxml-mode-test-indent-line-after-data ()
+  "Test indenting of lines after data or cdata"
+  (should (nxml-mode-tests-correctly-indented-string "
+<kml>
+  <description>
+    more</description>
+  <abc>data</abc>
+
+  <description>
+    more
+    <abc>data</abc>
+  </description>
+
+  <description>
+    more
+    <abc>
+      data
+    </abc>
+  </description>
+
+  <description>
+    <![CDATA[multi
+             line
+             data]]></description>
+  <abc>data</abc>
+
+  <description>
+    <![CDATA[multi
+             line
+             data]]>
+    <abc>data</abc>
+  </description>
+  <description>
+    <![CDATA[multi
+             line
+             data]]>
+    <abc>
+      data
+    </abc>
+  </description>
+</kml>
+")))
+
+
+(ert-deftest nxml-mode-test-multiple-start-tags-single-line ()
+  "Test for indent depth where multiple tags are on one line."
+  (should (nxml-mode-tests-correctly-indented-string "
+<kml>
+  <Document>
+    <Folder><name>abc</name>
+      <Folder><name>123</name>
+      </Folder>
+    </Folder>
+  </Document>
+</kml>"))
+  (should (nxml-mode-tests-correctly-indented-string "
+<kml>
+  <Document>
+    <Folder><name>abc</name>
+      <Folder></Folder>
+    </Folder>
+  </Document>
+</kml>"))
+  (should (nxml-mode-tests-correctly-indented-string "
+<kml>
+  <document></document>
+  <elm>
+    data
+  </elmh>
+  <a><b><c>
+        <d>data</d>
+  </c></b></a>
+  <a><b><c><inner /><d>
+          <e></e>
+  </d><inner /></c></b></a>
+  <single />
+  <one><two><three>
+        four
+      </three>
+    </two>
+  </one>
+  <one>
+    <two>
+      <three>
+        four
+  </three></two></one>
+  <one><two>
+      three<four>
+        five
+      </four>
+    </two>
+  </one>
+</kml>
+")))
+
 (provide 'nxml-mode-tests)
 ;;; nxml-mode-tests.el ends here

  parent reply	other threads:[~2023-03-28 19:05 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-01-29 21:47 bug#7937: nxml-mode.el indenting wrong when more than one <> on a line jidanni
2019-10-14 15:41 ` Stefan Kangas
2019-10-18  8:19 ` 積丹尼 Dan Jacobson
2020-08-07 10:32   ` Lars Ingebrigtsen
2023-03-28 19:05 ` Stephen Meister [this message]
2023-03-30  6:56   ` bug#7937: nxml-mode indenting bug fix Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAMrh0GMapEMPaeR=y=qYu8MHXpA5DhsSejcWXLMeWB4e_f26CA@mail.gmail.com' \
    --to=pallagun@gmail.com \
    --cc=7937@debbugs.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.