diff options
| author | Stefan Monnier | 2003-06-05 01:14:23 +0000 |
|---|---|---|
| committer | Stefan Monnier | 2003-06-05 01:14:23 +0000 |
| commit | 59444a9cccb3f5c10536f7bfcc776e9afa29438e (patch) | |
| tree | fad57c914470da77e230697e438af933e3a87f64 | |
| parent | a530382071fde731cc36c549ee9086ca19a345fb (diff) | |
| download | emacs-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.el | 231 |
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." | |||
| 1045 | Assume that parsing starts from within a textual context. | 1045 | Assume that parsing starts from within a textual context. |
| 1046 | Leave point at the beginning of the tag." | 1046 | Leave 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. |
| 1087 | If FULL is `empty', return even if the context is empty (i.e. | 1093 | By default, parse until we find a start-tag as the first thing on a line. |
| 1094 | If UNTIL is `empty', return even if the context is empty (i.e. | ||
| 1088 | we just skipped over some element and got to a beginning of line). | 1095 | we just skipped over some element and got to a beginning of line). |
| 1089 | If FULL is non-nil, parse back to the beginning of the buffer, otherwise | ||
| 1090 | parse until we find a start-tag as the first thing on a line. | ||
| 1091 | 1096 | ||
| 1092 | The context is a list of tag-info structures. The last one is the tag | 1097 | The context is a list of tag-info structures. The last one is the tag |
| 1093 | immediately enclosing the current position." | 1098 | immediately enclosing the current position. |
| 1099 | |||
| 1100 | Point is assumed to be outside of any tag. If we discover that it's | ||
| 1101 | not 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))) | 1225 | LCON 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'. |