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 " + + + ... + + +")) + (should (nxml-mode-tests-correctly-indented-string " + + more + data + + + more + data + + + + more + + data + + + + + + data + + + + data + + + + + data + + + +"))) + + +(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 " + + + abc + 123 + + + +")) + (should (nxml-mode-tests-correctly-indented-string " + + + abc + + + +")) + (should (nxml-mode-tests-correctly-indented-string " + + + + data + + + data + + + + + + + four + + + + + + + four + + + three + five + + + + +"))) + (provide 'nxml-mode-tests) ;;; nxml-mode-tests.el ends here