Subject: bug#5127: Indentation of top level tags when no single top level tag

From: Lennart Borgman <[email-masked]>
Date: Sat, 5 Dec 2009 00:17:40 +0100

Sometimes a user is working with part of a code and still want to do
indentation. In cases like this

              <head>
              </head>
              <body>

the body tag will currently be intended to column 0 by sgml-indent-line.

The attached patch handles this particular case specially to avoid
that. Since I do not want to change the return values from
sgml-geet-context (which is where this situation best can be detected)
I have transferred the extra information in a global variable
sgml-get-context-last-close instead.

This is against a checkout from 2009-12-04.
Index: sgml-mode.el
===================================================================
RCS file: /sources/emacs/emacs/lisp/textmodes/sgml-mode.el,v
retrieving revision 1.145
diff -c -r1.145 sgml-mode.el
*** sgml-mode.el	31 Oct 2009 21:52:56 -0000	1.145
--- sgml-mode.el	4 Dec 2009 23:04:06 -0000
***************
*** 1265,1270 ****
--- 1265,1274 ----
        (goto-char tag-start)
        (sgml-make-tag tag-type tag-start tag-end name))))
  
+ (defvar sgml-get-context-last-close nil
+   "Last close tag start.
+ Only used for outermost level.")
+ 
  (defun sgml-get-context (&optional until)
    "Determine the context of the current position.
  By default, parse until we find a start-tag as the first thing on a line.
***************
*** 1280,1291 ****
  	(stack nil)
  	(ignore nil)
  	(context nil)
! 	tag-info)
      ;; CONTEXT keeps track of the tag-stack
      ;; STACK keeps track of the end tags we've seen (and thus the start-tags
      ;;   we'll have to ignore) when skipping over matching open..close pairs.
      ;; IGNORE is a list of tags that can be ignored because they have been
      ;;   closed implicitly.
      (skip-chars-backward " \t\n")      ; Make sure we're not at indentation.
      (while
  	(and (not (eq until 'now))
--- 1284,1298 ----
  	(stack nil)
  	(ignore nil)
  	(context nil)
! 	tag-info
!         last-close)
      ;; CONTEXT keeps track of the tag-stack
      ;; STACK keeps track of the end tags we've seen (and thus the start-tags
      ;;   we'll have to ignore) when skipping over matching open..close pairs.
      ;; IGNORE is a list of tags that can be ignored because they have been
      ;;   closed implicitly.
+     ;; LAST-CLOSE is last close tag that can be useful for indentation
+     ;;   when on outermost level.
      (skip-chars-backward " \t\n")      ; Make sure we're not at indentation.
      (while
  	(and (not (eq until 'now))
***************
*** 1312,1317 ****
--- 1319,1327 ----
  
         ;; start-tag
         ((eq (sgml-tag-type tag-info) 'open)
+         (when (and (null stack)
+                    last-close)
+           (setq last-close 'no-use))
  	(cond
  	 ((null stack)
  	  (if (assoc-string (sgml-tag-name tag-info) ignore t)
***************
*** 1354,1363 ****
--- 1364,1389 ----
         ((eq (sgml-tag-type tag-info) 'close)
  	(if (sgml-empty-tag-p (sgml-tag-name tag-info))
  	    (message "Spurious </%s>: empty tag" (sgml-tag-name tag-info))
+           ;; Keep track of last close if context will return nil
+           (when (and (not last-close)
+                      (null stack)
+                      (> here (point-at-eol))
+                      (let ((here (point)))
+                        (goto-char (sgml-tag-start tag-info))
+                        (skip-chars-backward " \t")
+                        (prog1
+                            (bolp)
+                          (goto-char here))))
+             (setq last-close tag-info))
+ 
  	  (push (sgml-tag-name tag-info) stack)))
         ))
  
      ;; return context
+     (setq sgml-get-context-last-close
+           (when (and last-close
+                      (not (eq last-close 'no-use)))
+             (sgml-tag-start last-close)))
      context))
  
  (defun sgml-show-context (&optional full)
***************
*** 1508,1514 ****
  	      (< (point) here) (sgml-at-indentation-p))
  	 (current-column))
  	(t
! 	 (goto-char there)
  	 (+ (current-column)
  	    (* sgml-basic-offset (length context)))))))
  
--- 1534,1542 ----
  	      (< (point) here) (sgml-at-indentation-p))
  	 (current-column))
  	(t
! 	 (goto-char (or (and (null context)
!                              sgml-get-context-last-close)
!                         there))
  	 (+ (current-column)
  	    (* sgml-basic-offset (length context)))))))