aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2003-06-05 01:14:23 +0000
committerStefan Monnier2003-06-05 01:14:23 +0000
commit59444a9cccb3f5c10536f7bfcc776e9afa29438e (patch)
treefad57c914470da77e230697e438af933e3a87f64
parenta530382071fde731cc36c549ee9086ca19a345fb (diff)
downloademacs-59444a9cccb3f5c10536f7bfcc776e9afa29438e.tar.gz
emacs-59444a9cccb3f5c10536f7bfcc776e9afa29438e.zip
(sgml-parse-tag-backward): Try and detect
when we're starting from within a tag. (sgml-get-context): When called from inside a tag, do something useful. Rename the arg now that it's never used for `full' context anymore. (sgml-calculate-indent): Make `lcon' an argument. Return nil when we don't know what to do. If the initial lcon turns out to be wrong, try again. (sgml-indent-line): If sgml-calculate-indent returns nil, don't indent.
-rw-r--r--lisp/textmodes/sgml-mode.el231
1 files changed, 130 insertions, 101 deletions
diff --git a/lisp/textmodes/sgml-mode.el b/lisp/textmodes/sgml-mode.el
index 87c9e820e1f..d942c263274 100644
--- a/lisp/textmodes/sgml-mode.el
+++ b/lisp/textmodes/sgml-mode.el
@@ -368,8 +368,8 @@ Otherwise, it is set to be buffer-local when the file has
368 (looking-at "\\s-*<\\?xml") 368 (looking-at "\\s-*<\\?xml")
369 (when (re-search-forward 369 (when (re-search-forward
370 (eval-when-compile 370 (eval-when-compile
371 (mapconcat 'identity 371 (mapconcat 'identity
372 '("<!DOCTYPE" "\\(\\w+\\)" "\\(\\w+\\)" 372 '("<!DOCTYPE" "\\(\\w+\\)" "\\(\\w+\\)"
373 "\"\\([^\"]+\\)\"" "\"\\([^\"]+\\)\"") 373 "\"\\([^\"]+\\)\"" "\"\\([^\"]+\\)\"")
374 "\\s-+")) 374 "\\s-+"))
375 nil t) 375 nil t)
@@ -1045,8 +1045,14 @@ You might want to turn on `auto-fill-mode' to get better results."
1045Assume that parsing starts from within a textual context. 1045Assume that parsing starts from within a textual context.
1046Leave point at the beginning of the tag." 1046Leave point at the beginning of the tag."
1047 (let (tag-type tag-start tag-end name) 1047 (let (tag-type tag-start tag-end name)
1048 (or (search-backward ">" limit 'move) 1048 (or (re-search-backward "[<>]" limit 'move)
1049 (error "No tag found")) 1049 (error "No tag found"))
1050 (when (eq (char-after) ?<)
1051 ;; Oops!! Looks like we were not in a textual context after all!.
1052 ;; Let's try to recover.
1053 (with-syntax-table sgml-tag-syntax-table
1054 (forward-sexp)
1055 (forward-char -1)))
1050 (setq tag-end (1+ (point))) 1056 (setq tag-end (1+ (point)))
1051 (cond 1057 (cond
1052 ((sgml-looking-back-at "--") ; comment 1058 ((sgml-looking-back-at "--") ; comment
@@ -1082,15 +1088,17 @@ Leave point at the beginning of the tag."
1082 (goto-char tag-start) 1088 (goto-char tag-start)
1083 (sgml-make-tag tag-type tag-start tag-end name))) 1089 (sgml-make-tag tag-type tag-start tag-end name)))
1084 1090
1085(defun sgml-get-context (&optional full) 1091(defun sgml-get-context (&optional until)
1086 "Determine the context of the current position. 1092 "Determine the context of the current position.
1087If FULL is `empty', return even if the context is empty (i.e. 1093By default, parse until we find a start-tag as the first thing on a line.
1094If UNTIL is `empty', return even if the context is empty (i.e.
1088we just skipped over some element and got to a beginning of line). 1095we just skipped over some element and got to a beginning of line).
1089If FULL is non-nil, parse back to the beginning of the buffer, otherwise
1090parse until we find a start-tag as the first thing on a line.
1091 1096
1092The context is a list of tag-info structures. The last one is the tag 1097The context is a list of tag-info structures. The last one is the tag
1093immediately enclosing the current position." 1098immediately enclosing the current position.
1099
1100Point is assumed to be outside of any tag. If we discover that it's
1101not the case, the first tag returned is the one inside which we are."
1094 (let ((here (point)) 1102 (let ((here (point))
1095 (ignore nil) 1103 (ignore nil)
1096 (context nil) 1104 (context nil)
@@ -1101,12 +1109,13 @@ immediately enclosing the current position."
1101 ;; enclosing start-tags we'll have to ignore. 1109 ;; enclosing start-tags we'll have to ignore.
1102 (skip-chars-backward " \t\n") ; Make sure we're not at indentation. 1110 (skip-chars-backward " \t\n") ; Make sure we're not at indentation.
1103 (while 1111 (while
1104 (and (or ignore 1112 (and (not (eq until 'now))
1105 (not (if full (eq full 'empty) context)) 1113 (or ignore
1114 (not (if until (eq until 'empty) context))
1106 (not (sgml-at-indentation-p)) 1115 (not (sgml-at-indentation-p))
1107 (and context 1116 (and context
1108 (/= (point) (sgml-tag-start (car context))) 1117 (/= (point) (sgml-tag-start (car context)))
1109 (sgml-unclosed-tag-p (sgml-tag-name (car context))))) 1118 (sgml-unclosed-tag-p (sgml-tag-name (car context)))))
1110 (setq tag-info (ignore-errors (sgml-parse-tag-backward)))) 1119 (setq tag-info (ignore-errors (sgml-parse-tag-backward))))
1111 1120
1112 ;; This tag may enclose things we thought were tags. If so, 1121 ;; This tag may enclose things we thought were tags. If so,
@@ -1117,6 +1126,10 @@ immediately enclosing the current position."
1117 (setq context (cdr context))) 1126 (setq context (cdr context)))
1118 1127
1119 (cond 1128 (cond
1129 ((> (sgml-tag-end tag-info) here)
1130 ;; Oops!! Looks like we were not outside of any tag, after all.
1131 (push tag-info context)
1132 (setq until 'now))
1120 1133
1121 ;; start-tag 1134 ;; start-tag
1122 ((eq (sgml-tag-type tag-info) 'open) 1135 ((eq (sgml-tag-type tag-info) 'open)
@@ -1207,99 +1220,113 @@ the current start-tag or the current comment or the current cdata, ..."
1207 (and (not sgml-xml-mode) 1220 (and (not sgml-xml-mode)
1208 (member-ignore-case tag-name sgml-unclosed-tags))) 1221 (member-ignore-case tag-name sgml-unclosed-tags)))
1209 1222
1210(defun sgml-calculate-indent () 1223(defun sgml-calculate-indent (&optional lcon)
1211 "Calculate the column to which this line should be indented." 1224 "Calculate the column to which this line should be indented.
1212 (let ((lcon (sgml-lexical-context))) 1225LCON is the lexical context, if any."
1213 1226 (unless lcon (setq lcon (sgml-lexical-context)))
1214 ;; Indent comment-start markers inside <!-- just like comment-end markers. 1227
1215 (if (and (eq (car lcon) 'tag) 1228 ;; Indent comment-start markers inside <!-- just like comment-end markers.
1216 (looking-at "--") 1229 (if (and (eq (car lcon) 'tag)
1217 (save-excursion (goto-char (cdr lcon)) (looking-at "<!--"))) 1230 (looking-at "--")
1218 (setq lcon (cons 'comment (+ (cdr lcon) 2)))) 1231 (save-excursion (goto-char (cdr lcon)) (looking-at "<!--")))
1219 1232 (setq lcon (cons 'comment (+ (cdr lcon) 2))))
1220 (case (car lcon) 1233
1221 1234 (case (car lcon)
1222 (string 1235
1236 (string
1237 ;; Go back to previous non-empty line.
1238 (while (and (> (point) (cdr lcon))
1239 (zerop (forward-line -1))
1240 (looking-at "[ \t]*$")))
1241 (if (> (point) (cdr lcon))
1242 ;; Previous line is inside the string.
1243 (current-indentation)
1244 (goto-char (cdr lcon))
1245 (1+ (current-column))))
1246
1247 (comment
1248 (let ((mark (looking-at "--")))
1223 ;; Go back to previous non-empty line. 1249 ;; Go back to previous non-empty line.
1224 (while (and (> (point) (cdr lcon)) 1250 (while (and (> (point) (cdr lcon))
1225 (zerop (forward-line -1)) 1251 (zerop (forward-line -1))
1226 (looking-at "[ \t]*$"))) 1252 (or (looking-at "[ \t]*$")
1253 (if mark (not (looking-at "[ \t]*--"))))))
1227 (if (> (point) (cdr lcon)) 1254 (if (> (point) (cdr lcon))
1228 ;; Previous line is inside the string. 1255 ;; Previous line is inside the comment.
1229 (current-indentation) 1256 (skip-chars-forward " \t")
1230 (goto-char (cdr lcon)) 1257 (goto-char (cdr lcon))
1231 (1+ (current-column)))) 1258 ;; Skip `<!' to get to the `--' with which we want to align.
1232 1259 (search-forward "--")
1233 (comment 1260 (goto-char (match-beginning 0)))
1234 (let ((mark (looking-at "--"))) 1261 (when (and (not mark) (looking-at "--"))
1235 ;; Go back to previous non-empty line. 1262 (forward-char 2) (skip-chars-forward " \t"))
1236 (while (and (> (point) (cdr lcon)) 1263 (current-column)))
1237 (zerop (forward-line -1)) 1264
1238 (or (looking-at "[ \t]*$") 1265 ;; We don't know how to indent it. Let's be honest about it.
1239 (if mark (not (looking-at "[ \t]*--")))))) 1266 (cdata nil)
1240 (if (> (point) (cdr lcon)) 1267
1241 ;; Previous line is inside the comment. 1268 (tag
1242 (skip-chars-forward " \t") 1269 (goto-char (1+ (cdr lcon)))
1243 (goto-char (cdr lcon))) 1270 (skip-chars-forward "^ \t\n") ;Skip tag name.
1244 (when (and (not mark) (looking-at "--")) 1271 (skip-chars-forward " \t")
1245 (forward-char 2) (skip-chars-forward " \t")) 1272 (if (not (eolp))
1246 (current-column))) 1273 (current-column)
1247 1274 ;; This is the first attribute: indent.
1248 (cdata
1249 (current-column))
1250
1251 (tag
1252 (goto-char (1+ (cdr lcon))) 1275 (goto-char (1+ (cdr lcon)))
1253 (skip-chars-forward "^ \t\n") ;Skip tag name. 1276 (+ (current-column) sgml-basic-offset)))
1254 (skip-chars-forward " \t") 1277
1255 (if (not (eolp)) 1278 (text
1256 (current-column) 1279 (while (looking-at "</")
1257 ;; This is the first attribute: indent. 1280 (forward-sexp 1)
1258 (goto-char (1+ (cdr lcon))) 1281 (skip-chars-forward " \t"))
1259 (+ (current-column) sgml-basic-offset))) 1282 (let* ((here (point))
1260 1283 (unclosed (and ;; (not sgml-xml-mode)
1261 (text 1284 (looking-at sgml-tag-name-re)
1262 (while (looking-at "</") 1285 (member-ignore-case (match-string 1)
1263 (forward-sexp 1) 1286 sgml-unclosed-tags)
1264 (skip-chars-forward " \t")) 1287 (match-string 1)))
1265 (let* ((here (point)) 1288 (context
1266 (unclosed (and ;; (not sgml-xml-mode) 1289 ;; If possible, align on the previous non-empty text line.
1267 (looking-at sgml-tag-name-re) 1290 ;; Otherwise, do a more serious parsing to find the
1268 (member-ignore-case (match-string 1) 1291 ;; tag(s) relative to which we should be indenting.
1269 sgml-unclosed-tags) 1292 (if (and (not unclosed) (skip-chars-backward " \t")
1270 (match-string 1))) 1293 (< (skip-chars-backward " \t\n") 0)
1271 (context 1294 (back-to-indentation)
1272 ;; If possible, align on the previous non-empty text line. 1295 (> (point) (cdr lcon)))
1273 ;; Otherwise, do a more serious parsing to find the 1296 nil
1274 ;; tag(s) relative to which we should be indenting. 1297 (goto-char here)
1275 (if (and (not unclosed) (skip-chars-backward " \t") 1298 (nreverse (sgml-get-context (if unclosed nil 'empty)))))
1276 (< (skip-chars-backward " \t\n") 0) 1299 (there (point)))
1277 (back-to-indentation) 1300 ;; Ignore previous unclosed start-tag in context.
1278 (> (point) (cdr lcon))) 1301 (while (and context unclosed
1279 nil 1302 (eq t (compare-strings
1280 (goto-char here) 1303 (sgml-tag-name (car context)) nil nil
1281 (nreverse (sgml-get-context (if unclosed nil 'empty))))) 1304 unclosed nil nil t)))
1282 (there (point))) 1305 (setq context (cdr context)))
1283 ;; Ignore previous unclosed start-tag in context. 1306 ;; Indent to reflect nesting.
1284 (while (and context unclosed 1307 (cond
1285 (eq t (compare-strings 1308 ;; If we were not in a text context after all, let's try again.
1286 (sgml-tag-name (car context)) nil nil 1309 ((and context (> (sgml-tag-end (car context)) here))
1287 unclosed nil nil t))) 1310 (goto-char here)
1288 (setq context (cdr context))) 1311 (sgml-calculate-indent
1289 ;; Indent to reflect nesting. 1312 (cons (if (memq (sgml-tag-type (car context)) '(comment cdata))
1290 (if (and context 1313 (sgml-tag-type (car context)) 'tag)
1291 (goto-char (sgml-tag-end (car context))) 1314 (sgml-tag-start (car context)))))
1292 (skip-chars-forward " \t\n") 1315 ;; Align on the first element after the nearest open-tag, if any.
1293 (< (point) here) (sgml-at-indentation-p)) 1316 ((and context
1294 (current-column) 1317 (goto-char (sgml-tag-end (car context)))
1295 (goto-char there) 1318 (skip-chars-forward " \t\n")
1296 (+ (current-column) 1319 (< (point) here) (sgml-at-indentation-p))
1297 (* sgml-basic-offset (length context)))))) 1320 (current-column))
1298 1321 (t
1299 (otherwise 1322 (goto-char there)
1300 (error "Unrecognised context %s" (car lcon))) 1323 (+ (current-column)
1301 1324 (* sgml-basic-offset (length context)))))))
1302 ))) 1325
1326 (otherwise
1327 (error "Unrecognised context %s" (car lcon)))
1328
1329 ))
1303 1330
1304(defun sgml-indent-line () 1331(defun sgml-indent-line ()
1305 "Indent the current line as SGML." 1332 "Indent the current line as SGML."
@@ -1310,9 +1337,11 @@ the current start-tag or the current comment or the current cdata, ..."
1310 (back-to-indentation) 1337 (back-to-indentation)
1311 (if (>= (point) savep) (setq savep nil)) 1338 (if (>= (point) savep) (setq savep nil))
1312 (sgml-calculate-indent)))) 1339 (sgml-calculate-indent))))
1313 (if savep 1340 (if (null indent-col)
1314 (save-excursion (indent-line-to indent-col)) 1341 'noindent
1315 (indent-line-to indent-col)))) 1342 (if savep
1343 (save-excursion (indent-line-to indent-col))
1344 (indent-line-to indent-col)))))
1316 1345
1317(defun sgml-guess-indent () 1346(defun sgml-guess-indent ()
1318 "Guess an appropriate value for `sgml-basic-offset'. 1347 "Guess an appropriate value for `sgml-basic-offset'.