diff options
Diffstat (limited to 'lisp/textmodes/tex-mode.el')
-rw-r--r-- | lisp/textmodes/tex-mode.el | 203 |
1 files changed, 153 insertions, 50 deletions
diff --git a/lisp/textmodes/tex-mode.el b/lisp/textmodes/tex-mode.el index a42a195b8ec..ffb06061bb6 100644 --- a/lisp/textmodes/tex-mode.el +++ b/lisp/textmodes/tex-mode.el @@ -1,7 +1,8 @@ ;;; tex-mode.el --- TeX, LaTeX, and SliTeX mode commands -*- coding: utf-8 -*- -;; Copyright (C) 1985, 1986, 1989, 1992, 1994, 1995, 1996, 1997, 1998, 1999, -;; 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +;; Copyright (C) 1985, 1986, 1989, 1992, 1994, 1995, 1996, 1997, 1998 +;; 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +;; Free Software Foundation, Inc. ;; Maintainer: FSF ;; Keywords: tex @@ -243,6 +244,24 @@ Normally set to either `plain-tex-mode' or `latex-mode'." :options '("''" "\">" "\"'" ">>" "ยป") :group 'tex) +(defcustom tex-fontify-script t + "If non-nil, fontify subscript and superscript strings." + :type 'boolean + :group 'tex + :version "23.1") +(put 'tex-fontify-script 'safe-local-variable 'booleanp) + +(defcustom tex-font-script-display '(-0.2 0.2) + "How much to lower and raise subscript and superscript content. +This is a list of two floats. The first is negative and +specifies how much subscript is lowered, the second is positive +and specifies how much superscript is raised. Heights are +measured relative to that of the normal text." + :group 'tex + :type '(list (float :tag "Subscript") + (float :tag "Superscript")) + :version "23.1") + (defvar tex-last-temp-file nil "Latest temporary file generated by \\[tex-region] and \\[tex-buffer]. Deleted when the \\[tex-region] or \\[tex-buffer] is next run, or when the @@ -527,6 +546,8 @@ An alternative value is \" . \", if you use a font with a narrow period." (citations (regexp-opt '("label" "ref" "pageref" "vref" "eqref" "cite" "nocite" "index" "glossary" "bibitem" + ;; natbib's two variants of \cite: + "citep" "citet" ;; These are text, rather than citations. ;; "caption" "footnote" "footnotemark" "footnotetext" ) @@ -591,13 +612,14 @@ An alternative value is \" . \", if you use a font with a narrow period." (setq pos (1- pos) odd (not odd))) odd)) (if (eq (char-after pos) ?_) - '(face subscript display (raise -0.3)) - '(face superscript display (raise +0.3))))) + `(face subscript display (raise ,(car tex-font-script-display))) + `(face superscript display (raise ,(cadr tex-font-script-display)))))) (defun tex-font-lock-match-suscript (limit) "Match subscript and superscript patterns up to LIMIT." - (when (re-search-forward "[_^] *\\([^\n\\{}]\\|\ -\\\\\\([a-zA-Z@]+\\|[^ \t\n]\\)\\|\\({\\)\\)" limit t) + (when (and tex-fontify-script + (re-search-forward "[_^] *\\([^\n\\{}]\\|\ +\\\\\\([a-zA-Z@]+\\|[^ \t\n]\\)\\|\\({\\)\\)" limit t)) (when (match-end 3) (let ((beg (match-beginning 3)) (end (save-restriction @@ -619,26 +641,31 @@ An alternative value is \" . \", if you use a font with a narrow period." (defvar tex-verbatim-environments '("verbatim" "verbatim*")) +(put 'tex-verbatim-environments 'safe-local-variable + (lambda (x) (null (delq t (mapcar 'stringp x))))) (defvar tex-font-lock-syntactic-keywords - (let ((verbs (regexp-opt tex-verbatim-environments t))) - `((,(concat "^\\\\begin *{" verbs "}.*\\(\n\\)") 2 "|") - ;; Technically, we'd like to put the "|" property on the \n preceding - ;; the \end, but this would have 2 disadvantages: - ;; 1 - it's wrong if the verbatim env is empty (the same \n is used to - ;; start and end the fenced-string). - ;; 2 - font-lock considers the preceding \n as being part of the - ;; preceding line, so things gets screwed every time the previous - ;; line is re-font-locked on its own. - ;; There's a hack in tex-font-lock-keywords-1 to remove the verbatim - ;; face from the \ but C-M-f still jumps to the wrong spot :-( --Stef - (,(concat "^\\(\\\\\\)end *{" verbs "}\\(.?\\)") (1 "|") (3 "<")) - ;; ("^\\(\\\\\\)begin *{comment}" 1 "< b") - ;; ("^\\\\end *{comment}.*\\(\n\\)" 1 "> b") - ("\\\\verb\\**\\([^a-z@*]\\)" - ;; Do it last, because it uses syntax-ppss which needs the - ;; syntax-table properties of previous entries. - 1 (tex-font-lock-verb (match-end 1)))))) + '((eval . `(,(concat "^\\\\begin *{" + (regexp-opt tex-verbatim-environments t) + "}.*\\(\n\\)") 2 "|")) + ;; Technically, we'd like to put the "|" property on the \n preceding + ;; the \end, but this would have 2 disadvantages: + ;; 1 - it's wrong if the verbatim env is empty (the same \n is used to + ;; start and end the fenced-string). + ;; 2 - font-lock considers the preceding \n as being part of the + ;; preceding line, so things gets screwed every time the previous + ;; line is re-font-locked on its own. + ;; There's a hack in tex-font-lock-keywords-1 to remove the verbatim + ;; face from the \ but C-M-f still jumps to the wrong spot :-( --Stef + (eval . `(,(concat "^\\(\\\\\\)end *{" + (regexp-opt tex-verbatim-environments t) + "}\\(.?\\)") (1 "|") (3 "<"))) + ;; ("^\\(\\\\\\)begin *{comment}" 1 "< b") + ;; ("^\\\\end *{comment}.*\\(\n\\)" 1 "> b") + ("\\\\verb\\**\\([^a-z@*]\\)" + ;; Do it last, because it uses syntax-ppss which needs the + ;; syntax-table properties of previous entries. + 1 (tex-font-lock-verb (match-end 1))))) (defun tex-font-lock-unfontify-region (beg end) (font-lock-default-unfontify-region beg end) @@ -646,17 +673,47 @@ An alternative value is \" . \", if you use a font with a narrow period." (let ((next (next-single-property-change beg 'display nil end)) (prop (get-text-property beg 'display))) (if (and (eq (car-safe prop) 'raise) - (member (car-safe (cdr prop)) '(-0.3 +0.3)) + (member (car-safe (cdr prop)) tex-font-script-display) (null (cddr prop))) (put-text-property beg next 'display nil)) (setq beg next)))) +(defcustom tex-suscript-height-ratio 0.8 + "Ratio of subscript/superscript height to that of the preceding text. +In nested subscript/superscript, this factor is applied repeatedly, +subject to the limit set by `tex-suscript-height-minimum'." + :type 'float + :group 'tex + :version "23.1") + +(defcustom tex-suscript-height-minimum 0.0 + "Integer or float limiting the minimum size of subscript/superscript text. +An integer is an absolute height in units of 1/10 point, a float +is a height relative to that of the default font. Zero means no minimum." + :type '(choice (integer :tag "Integer height in 1/10 point units") + (float :tag "Fraction of default font height")) + :group 'tex + :version "23.1") + +(defun tex-suscript-height (height) + "Return the integer height of subscript/superscript font in 1/10 points. +Not smaller than the value set by `tex-suscript-height-minimum'." + (ceiling (max (if (integerp tex-suscript-height-minimum) + tex-suscript-height-minimum + ;; For bootstrapping. + (condition-case nil + (* tex-suscript-height-minimum + (face-attribute 'default :height)) + (error 0))) + ;; NB assumes height is integer. + (* height tex-suscript-height-ratio)))) + (defface superscript - '((t :height 0.8)) ;; :raise 0.3 + '((t :height tex-suscript-height)) ;; :raise 0.2 "Face used for superscripts." :group 'tex) (defface subscript - '((t :height 0.8)) ;; :raise -0.3 + '((t :height tex-suscript-height)) ;; :raise -0.2 "Face used for subscripts." :group 'tex) @@ -1169,14 +1226,14 @@ on the line for the invalidity you want to see." (backward-paragraph) (forward-paragraph) (while (not (bobp)) - ;; Scan the previous paragraph for invalidities. + ;; Scan the previous paragraph for invalidities. (backward-paragraph) (save-excursion (or (tex-validate-region (point) (save-excursion (forward-paragraph) (point))) (let ((end (line-beginning-position 2)) - start tem) + start tem) (beginning-of-line) (setq start (point)) ;; Keep track of line number as we scan, @@ -1240,6 +1297,7 @@ area if a mismatch is found." (save-excursion (let ((pos (match-beginning 0))) (goto-char pos) + (skip-chars-backward "\\\\") ; escaped parens (forward-sexp 1) (or (eq (preceding-char) (cdr (syntax-after pos))) (eq (char-after pos) (cdr (syntax-after (1- (point))))) @@ -1378,6 +1436,34 @@ Return the value returned by the last execution of BODY." (looking-at "\\\\begin"))) (tex-next-unmatched-end))) +(defun tex-next-unmatched-eparen (otype) + "Leave point after the next unmatched escaped closing parenthesis. +The string OTYPE is an opening parenthesis type: `(', `{', or `['." + (condition-case nil + (let ((ctype (char-to-string (cdr (aref (syntax-table) + (string-to-char otype)))))) + (while (and (tex-search-noncomment + (re-search-forward (format "\\\\[%s%s]" ctype otype))) + (save-excursion + (goto-char (match-beginning 0)) + (looking-at (format "\\\\%s" (regexp-quote otype))))) + (tex-next-unmatched-eparen otype))) + (wrong-type-argument (error "Unknown opening parenthesis type: %s" otype)) + (search-failed (error "Couldn't find closing escaped paren")))) + +(defun tex-last-unended-eparen (ctype) + "Leave point at the start of the last unended escaped opening parenthesis. +The string CTYPE is a closing parenthesis type: `)', `}', or `]'." + (condition-case nil + (let ((otype (char-to-string (cdr (aref (syntax-table) + (string-to-char ctype)))))) + (while (and (tex-search-noncomment + (re-search-backward (format "\\\\[%s%s]" ctype otype))) + (looking-at (format "\\\\%s" (regexp-quote ctype)))) + (tex-last-unended-eparen ctype))) + (wrong-type-argument (error "Unknown opening parenthesis type: %s" ctype)) + (search-failed (error "Couldn't find unended escaped paren")))) + (defun tex-goto-last-unclosed-latex-block () "Move point to the last unclosed \\begin{...}. Mark is left at original location." @@ -1389,26 +1475,34 @@ Mark is left at original location." (push-mark) (goto-char spot))) +;; Don't think this one actually _needs_ (for the purposes of +;; tex-mode) to handle escaped parens. (defun latex-backward-sexp-1 () - "Like (backward-sexp 1) but aware of multi-char elements." + "Like (backward-sexp 1) but aware of multi-char elements and escaped parens." (let ((pos (point)) (forward-sexp-function)) (backward-sexp 1) - (if (looking-at "\\\\begin\\>") - (signal 'scan-error - (list "Containing expression ends prematurely" - (point) (prog1 (point) (goto-char pos)))) - (when (eq (char-after) ?{) - (let ((newpos (point))) - (when (ignore-errors (backward-sexp 1) t) - (if (or (looking-at "\\\\end\\>") - ;; In case the \\ ends a verbatim section. - (and (looking-at "end\\>") (eq (char-before) ?\\))) - (tex-last-unended-begin) - (goto-char newpos)))))))) - + (cond ((looking-at "\\\\\\(begin\\>\\|[[({]\\)") + (signal 'scan-error + (list "Containing expression ends prematurely" + (point) (prog1 (point) (goto-char pos))))) + ((looking-at "\\\\\\([])}]\\)") + (tex-last-unended-eparen (match-string 1))) + ((eq (char-after) ?{) + (let ((newpos (point))) + (when (ignore-errors (backward-sexp 1) t) + (if (or (looking-at "\\\\end\\>") + ;; In case the \\ ends a verbatim section. + (and (looking-at "end\\>") (eq (char-before) ?\\))) + (tex-last-unended-begin) + (goto-char newpos)))))))) + +;; Note this does not handle things like mismatched brackets inside +;; begin/end blocks. +;; Needs to handle escaped parens for tex-validate-*. +;; http://lists.gnu.org/archive/html/bug-gnu-emacs/2007-09/msg00038.html (defun latex-forward-sexp-1 () - "Like (forward-sexp 1) but aware of multi-char elements." + "Like (forward-sexp 1) but aware of multi-char elements and escaped parens." (let ((pos (point)) (forward-sexp-function)) (forward-sexp 1) @@ -1425,10 +1519,19 @@ Mark is left at original location." ((looking-at "\\\\begin\\>") (goto-char (match-end 0)) (tex-next-unmatched-end)) + ;; A better way to handle this, \( .. \) etc, is probably to + ;; temporarily change the syntax of the \ in \( to punctuation. + ((looking-back "\\\\[])}]") + (signal 'scan-error + (list "Containing expression ends prematurely" + (- (point) 2) (prog1 (point) + (goto-char pos))))) + ((looking-back "\\\\\\([({[]\\)") + (tex-next-unmatched-eparen (match-string 1))) (t (goto-char newpos)))))) (defun latex-forward-sexp (&optional arg) - "Like `forward-sexp' but aware of multi-char elements." + "Like `forward-sexp' but aware of multi-char elements and escaped parens." (interactive "P") (unless arg (setq arg 1)) (let ((pos (point))) @@ -2169,7 +2272,7 @@ start of the header is required to be within the first 100 lines." (widen) (goto-char (point-min)) (let ((search-end (save-excursion - (forward-line 100) + (forward-line 100) (point))) (already-output 0) hbeg hend) @@ -2186,11 +2289,11 @@ start of the header is required to be within the first 100 lines." (and tex-start-of-header (re-search-forward tex-start-of-header search-end t) (progn - (beginning-of-line) - (setq hbeg (point)) ;mark beginning of header + (beginning-of-line) + (setq hbeg (point)) ; mark beginning of header (when (re-search-forward tex-end-of-header nil t) - (forward-line 1) - (setq hend (point)) ;mark end of header + (forward-line 1) + (setq hend (point)) ; mark end of header (write-region (max (if beg (min hbeg beg) |