yuuji@287: ;;; yatexenv.el --- YaTeX environment-specific functions yuuji@443: ;;; (c) 1994-2017 by HIROSE Yuuji.[yuuji@yatex.org] yuuji@497: ;;; Last modified Sun Sep 17 10:23:16 2017 on firestorm yuuji@366: ;;; $Id$ yuuji@23: yuuji@287: ;;; Code: yuuji@23: ;;; yuuji@23: ;; Functions for tabular environment yuuji@23: ;;; yuuji@23: yuuji@23: ;; Showing the matching column of tabular environment. yuuji@80: (defun YaTeX-array-what-column-internal () yuuji@80: "Return the cons of matching column and its title of array environment. yuuji@23: When calling from a program, make sure to be in array/tabular environment." yuuji@359: (let ((p (point)) bot beg eot bor eoll (nlptn "\\\\\\\\") (andptn "[^\\]&") yuuji@49: (n 0) j yuuji@23: (firsterr "This line might be the first row.")) yuuji@23: (save-excursion yuuji@23: (YaTeX-beginning-of-environment) yuuji@359: (setq eoll (save-excursion ;end of logical line yuuji@359: (YaTeX-goto-corresponding-environment) (point))) yuuji@23: (search-forward "{" p) (up-list 1) yuuji@23: (search-forward "{" p) (up-list 1) yuuji@23: ;;(re-search-forward andptn p) yuuji@359: (setq bot (point)) ;beginning of tabular yuuji@359: (while (progn (search-forward "&" eoll) yuuji@23: (equal (char-after (1- (match-beginning 0))) ?\\ ))) yuuji@23: (setq beg (1- (point))) ;beg is the point of the first & yuuji@359: (or (re-search-forward nlptn eoll t) yuuji@23: (error firsterr)) yuuji@23: (setq eot (point)) ;eot is the point of the first \\ yuuji@23: (goto-char p) yuuji@359: (setq bor (if (re-search-backward nlptn bot 1) yuuji@359: (point) ;bor is the beginning of this row. yuuji@359: bot)) yuuji@23: (while (< (1- (point)) p) yuuji@23: (if (equal (following-char) ?&) yuuji@23: (forward-char 1) yuuji@23: (re-search-forward andptn nil 1)) yuuji@23: (setq n (1+ n))) ;Check current column number yuuji@23: (goto-char p) yuuji@23: (cond ;Start searching \multicolumn{N} yuuji@23: ((> n 1) yuuji@23: (re-search-backward andptn) ;Sure to find! yuuji@23: (while (re-search-backward "\\\\multicolumn{\\([0-9]+\\)}" bor t) yuuji@452: (setq n (+ n (YaTeX-str2int yuuji@23: (buffer-substring (match-beginning 1) yuuji@23: (match-end 1))) yuuji@23: -1))))) yuuji@23: (message "%s" n) yuuji@23: (goto-char (1- beg)) yuuji@59: (beginning-of-line) yuuji@49: (setq j n) yuuji@49: (while (> j 1) yuuji@49: (or (re-search-forward andptn p nil) yuuji@49: (error "This column exceeds the limit.")) yuuji@49: (setq j (1- j))) yuuji@49: (skip-chars-forward "\\s ") yuuji@80: (list n yuuji@359: (YaTeX-buffer-substring yuuji@359: (progn (skip-chars-forward "\n \t") (point)) yuuji@80: (progn yuuji@80: (re-search-forward (concat andptn "\\|" nlptn) eot) yuuji@80: (goto-char (match-beginning 0)) yuuji@80: (if (looking-at andptn) yuuji@80: (forward-char 1)) yuuji@80: (skip-chars-backward "\\s ") yuuji@80: (point))))))) yuuji@80: yuuji@80: (defun YaTeX-array-what-column () yuuji@80: "Show matching column title of array environment. yuuji@80: When calling from a program, make sure to be in array/tabular environment." yuuji@80: (apply 'message yuuji@80: "This is the column(#%d) of: %s" yuuji@80: (YaTeX-array-what-column-internal))) yuuji@23: yuuji@23: ;;;###autoload yuuji@23: (defun YaTeX-what-column () yuuji@23: "Show which kind of column the current position is belonging to." yuuji@23: (interactive) yuuji@23: (cond yuuji@23: ((YaTeX-quick-in-environment-p '("tabular" "tabular*" "array" "array*")) yuuji@23: (YaTeX-array-what-column)) yuuji@80: (t (message "Not in array/tabular environment.")))) yuuji@23: yuuji@80: (defun YaTeX-tabular-parse-format-count-cols (beg end) yuuji@80: (goto-char beg) yuuji@80: (let (elt (cols 0)) yuuji@80: (while (< (point) end) yuuji@31: (setq elt (following-char)) yuuji@31: (cond yuuji@31: ((string-match (char-to-string elt) "clr") ;normal indicators. yuuji@31: (setq cols (1+ cols)) yuuji@31: (forward-char 1)) yuuji@31: ((equal elt ?|) ;vertical yuuji@31: (forward-char 1)) yuuji@31: ((string-match (char-to-string elt) "p@") ;p or @ expression yuuji@31: (setq cols (+ (if (eq elt ?p) 1 0) cols)) yuuji@80: ;;(skip-chars-forward "^{" p) yuuji@80: (skip-chars-forward "^{" end) yuuji@56: (forward-list 1)) yuuji@80: ((equal elt ?*) ;*{N}{EXP} -> Repeat EXP N times yuuji@80: (skip-chars-forward "^{" end) yuuji@452: (setq cols (* (YaTeX-str2int yuuji@80: (buffer-substring yuuji@80: (1+ (point)) yuuji@80: (progn (forward-list 1) (1- (point))))) yuuji@80: (YaTeX-tabular-parse-format-count-cols yuuji@80: (progn (skip-chars-forward "^{" end) (1+ (point))) yuuji@80: (progn (forward-list 1) (1- (point))))))) yuuji@56: (t (forward-char 1)) ;unknown char yuuji@56: )) yuuji@80: cols)) yuuji@80: yuuji@80: (defun YaTeX-tabular-parse-format (&optional type) yuuji@80: "Parse `tabular' format. yuuji@80: Return the list of (No.ofCols PointEndofFormat)" yuuji@80: (let ((p (point)) boform eoform (cols 0)) yuuji@80: (save-excursion yuuji@80: (if (null (YaTeX-beginning-of-environment t)) yuuji@80: (error "Beginning of tabular not found.")) yuuji@80: (skip-chars-forward "^{") yuuji@80: (forward-list 1) yuuji@80: (cond yuuji@80: ((eq type 'tabular*) yuuji@80: (skip-chars-forward "^{") yuuji@80: (forward-list 1))) yuuji@80: (skip-chars-forward "^{" p) yuuji@80: (if (/= (following-char) ?\{) (error "Tabular format not found.")) yuuji@80: (setq boform (1+ (point)) yuuji@80: eoform (progn (forward-list 1) (1- (point)))) yuuji@80: (if (> eoform p) (error "Non-terminated tabular format.")) yuuji@80: (goto-char boform) yuuji@80: (setq cols yuuji@80: (cond yuuji@80: ((eq type 'alignat) yuuji@80: (max yuuji@80: 1 yuuji@452: (* 2 (YaTeX-str2int yuuji@250: (buffer-substring yuuji@250: (point) yuuji@250: (progn (up-list -1) (forward-list 1) (1- (point)))))))) yuuji@80: (t yuuji@80: (YaTeX-tabular-parse-format-count-cols (point) eoform)))) yuuji@80: (list cols (1+ eoform))))) yuuji@80: yuuji@31: ;; Insert & yuuji@80: (defun YaTeX-intelligent-newline-tabular (&optional type) yuuji@31: "Parse current tabular format and insert that many `&'s." yuuji@80: (let*((p (point)) (format (YaTeX-tabular-parse-format type)) yuuji@31: (cols (car format)) (beg (car (cdr format))) yuuji@31: space hline) yuuji@58: (cond yuuji@58: ((search-backward "&" beg t) yuuji@58: (goto-char p) yuuji@58: (setq hline (search-backward "\\hline" beg t)) yuuji@58: (setq space (if (search-backward "\t&" beg t) "\t" " ")) yuuji@58: (goto-char p)) yuuji@58: (t ;;(insert "\\hline\n") yuuji@58: (setq space " "))) yuuji@31: (goto-char p) yuuji@31: (while (> (1- cols) 0) yuuji@31: (insert "&" space) yuuji@31: (setq cols (1- cols))) yuuji@31: (insert "\\\\") yuuji@31: (if hline (insert " \\hline")) yuuji@58: (goto-char p) yuuji@80: (YaTeX-indent-line))) yuuji@31: yuuji@31: (defun YaTeX-intelligent-newline-tabular* () yuuji@31: "Parse current tabular* format and insert that many `&'s." yuuji@80: (YaTeX-intelligent-newline-tabular 'tabular*)) yuuji@31: yuuji@31: (fset 'YaTeX-intelligent-newline-array 'YaTeX-intelligent-newline-tabular) yuuji@80: (fset 'YaTeX-intelligent-newline-supertabular 'YaTeX-intelligent-newline-tabular) yuuji@306: (fset 'YaTeX-intelligent-newline-longtable 'YaTeX-intelligent-newline-tabular) yuuji@80: yuuji@80: (defun YaTeX-intelligent-newline-align () yuuji@80: "Intelligent newline function for align. yuuji@80: Count the number of & in the first align line and insert that many &s." yuuji@250: (let*((p (point)) (amps 0)) yuuji@250: (if (string-match "alignat" env) yuuji@250: (setq amps (1- (car (YaTeX-tabular-parse-format 'alignat)))) yuuji@250: (save-excursion yuuji@250: (YaTeX-beginning-of-environment) yuuji@250: (catch 'done yuuji@250: (while (YaTeX-re-search-active-forward yuuji@250: "\\(&\\)\\|\\(\\\\\\\\\\)" YaTeX-comment-prefix p t) yuuji@250: (if (match-beginning 1) (setq amps (1+ amps)) (throw 'done t)))))) yuuji@80: (save-excursion yuuji@250: (forward-line -1) yuuji@250: (skip-chars-forward " \t") yuuji@250: (or (prog1 (looking-at "\\\\begin{") (end-of-line)) yuuji@250: (save-excursion yuuji@250: (skip-chars-backward " \t") yuuji@250: (and (= (preceding-char) ?\\) (= (char-after (- (point) 2)) ?\\))) yuuji@250: (insert "\\\\"))) yuuji@80: (save-excursion yuuji@250: (while (>= (setq amps (1- amps)) 0) yuuji@236: (insert "& "))) yuuji@80: (YaTeX-indent-line))) yuuji@80: yuuji@80: (mapcar yuuji@353: (function yuuji@353: (lambda (s) yuuji@80: (fset (intern (concat "YaTeX-intelligent-newline-" yuuji@80: (symbol-name s))) yuuji@353: 'YaTeX-intelligent-newline-align))) yuuji@80: '(align* flalign flalign* matrix pmatrix bmatrix Bmatrix vmatrix Vmatrix yuuji@250: cases eqnarray eqnarray* alignat alignat*)) yuuji@31: yuuji@23: ;;; yuuji@23: ;; Functions for tabbing environment yuuji@23: ;;; yuuji@23: (defun YaTeX-intelligent-newline-tabbing () yuuji@23: "Check the number of \\= in the first line and insert that many \\>." yuuji@23: (let ((p (point)) begenv tabcount) yuuji@23: (save-excursion yuuji@23: (YaTeX-beginning-of-environment) yuuji@23: (setq begenv (point-end-of-line)) yuuji@23: (if (YaTeX-search-active-forward "\\\\" YaTeX-comment-prefix p t) yuuji@23: (progn yuuji@23: (setq tabcount 0) yuuji@23: (while (> (point) begenv) yuuji@23: (if (search-backward "\\=" begenv 1) yuuji@23: (setq tabcount (1+ tabcount))))))) yuuji@23: (YaTeX-indent-line) yuuji@23: (if tabcount yuuji@23: (progn yuuji@23: (save-excursion yuuji@23: (while (> tabcount 0) yuuji@23: (insert "\\>\t") yuuji@23: (setq tabcount (1- tabcount)))) yuuji@23: (forward-char 2)) yuuji@58: (insert "\\= \\\\") yuuji@233: (forward-char -5)))) yuuji@23: yuuji@23: ;;; yuuji@23: ;; Functions for itemize/enumerate/list environments yuuji@23: ;;; yuuji@23: yuuji@23: (defun YaTeX-intelligent-newline-itemize () yuuji@23: "Insert '\\item '." yuuji@58: (insert "\\item ") yuuji@233: (YaTeX-indent-line)) yuuji@233: yuuji@23: (fset 'YaTeX-intelligent-newline-enumerate 'YaTeX-intelligent-newline-itemize) yuuji@23: (fset 'YaTeX-intelligent-newline-list 'YaTeX-intelligent-newline-itemize) yuuji@23: yuuji@23: (defun YaTeX-intelligent-newline-description () yuuji@23: (insert "\\item[] ") yuuji@23: (forward-char -2) yuuji@233: (YaTeX-indent-line)) yuuji@23: yuuji@64: (defun YaTeX-intelligent-newline-thebibliography () yuuji@64: "Insert '\\bibitem '." yuuji@64: (YaTeX-indent-line) yuuji@64: (YaTeX-make-section nil nil nil "bibitem") yuuji@233: (YaTeX-indent-line)) yuuji@233: yuuji@23: ;;; yuuji@234: ;; For document environment yuuji@234: ;;; yuuji@234: (defun YaTeX-intelligent-newline-document () yuuji@239: "New paragraph by null line or `\\par'." yuuji@257: (if (< (count-lines yuuji@257: (or (get 'YaTeX-inner-environment 'point) yuuji@257: (max 1 (- (point) 17))) ;"\begin{document}\n" == 17 yuuji@257: (point)) yuuji@257: 2) yuuji@257: nil yuuji@257: (if (save-excursion (re-search-backward "\\\\par\\>" nil t)) yuuji@257: (progn yuuji@257: (YaTeX-indent-line) yuuji@257: (insert "\\par"))) yuuji@257: (newline)) yuuji@239: (YaTeX-indent-line)) yuuji@234: yuuji@234: ;;; yuuji@23: ;; Intelligent newline yuuji@23: ;;; yuuji@23: ;;;###autoload yuuji@23: (defun YaTeX-intelligent-newline (arg) yuuji@23: "Insert newline and environment-specific entry. yuuji@23: `\\item' for some itemizing environment, yuuji@23: `\\> \\> \\' for tabbing environemnt, yuuji@23: `& & \\ \hline' for tabular environment." yuuji@23: (interactive "P") yuuji@61: (let*(env func) yuuji@61: (end-of-line) yuuji@61: (setq env (YaTeX-inner-environment)) yuuji@23: (if arg (setq env (YaTeX-read-environment "For what environment? "))) yuuji@23: (setq func (intern-soft (concat "YaTeX-intelligent-newline-" env))) yuuji@23: (end-of-line) yuuji@23: (newline) yuuji@58: (undo-boundary) yuuji@23: (if (and env func (fboundp func)) yuuji@80: (funcall func)))) yuuji@53: yuuji@53: ;;; yuuji@53: ;; Environment-specific line indenting functions yuuji@53: ;;; yuuji@53: ;;;###autoload yuuji@53: (defun YaTeX-indent-line-equation () yuuji@53: "Indent a line in equation family." yuuji@53: (let ((p (point)) (l-r 0) right-p peol depth (mp YaTeX-environment-indent)) yuuji@53: (if (save-excursion yuuji@53: (beginning-of-line) yuuji@53: (skip-chars-forward " \t") yuuji@53: (looking-at "\\\\right\\b")) yuuji@53: (progn (YaTeX-reindent yuuji@53: (save-excursion (YaTeX-goto-corresponding-leftright) yuuji@73: (- (current-column) 0)))) yuuji@53: (save-excursion yuuji@53: (forward-line -1) yuuji@53: (while (and (not (bobp)) (YaTeX-on-comment-p)) yuuji@53: (forward-line -1)) yuuji@53: ;;(beginning-of-line) ;must be unnecessary yuuji@53: (skip-chars-forward " \t") yuuji@53: (if (eolp) (error "Math-environment can't have a null line!!")) yuuji@53: (setq depth (current-column) yuuji@53: peol (point-end-of-line)) yuuji@53: (while (re-search-forward yuuji@53: "\\\\\\(\\(left\\)\\|\\(right\\)\\)\\b" peol t) yuuji@53: (setq l-r (+ l-r (if (match-beginning 2) 1 -1)))) yuuji@53: (cond yuuji@53: ((progn (beginning-of-line) yuuji@53: (re-search-forward "\\\\\\\\\\s *$" (point-end-of-line) t)) yuuji@53: ;;If previous line has `\\', this indentation is always normal. yuuji@53: (setq depth (+ (YaTeX-current-indentation) mp))) yuuji@53: ((> l-r 0) yuuji@53: (beginning-of-line) yuuji@68: (search-forward "\\left" peol nil l-r) yuuji@53: (goto-char (1+ (match-beginning 0))) yuuji@53: (setq depth (current-column))) yuuji@53: ((< l-r 0) yuuji@53: (goto-char (match-beginning 0)) ;should be \right yuuji@53: (YaTeX-goto-corresponding-leftright) yuuji@53: (beginning-of-line) yuuji@53: (skip-chars-forward " \t") yuuji@68: ;(setq depth (+ (current-column) mp)) ;+mp is good? yuuji@68: (setq depth (current-column))) yuuji@53: (t ;if \left - \right = 0 yuuji@53: (cond yuuji@53: ((re-search-forward "\\\\\\\\\\s *$" peol t) yuuji@53: (setq depth (+ (YaTeX-current-indentation) mp))) yuuji@53: ((re-search-forward "\\\\end{" peol t) yuuji@53: nil) ;same indentation as previous line's yuuji@53: ((re-search-forward "\\\\begin{" peol t) yuuji@53: (setq depth (+ depth mp))) yuuji@53: (t yuuji@53: (or (bobp) (forward-line -1)) yuuji@53: (cond yuuji@53: ((re-search-forward yuuji@53: "\\\\\\\\\\s *$\\|\\\\begin{" (point-end-of-line) t) yuuji@53: (setq depth (+ depth mp))) yuuji@53: ))))) yuuji@53: (goto-char p)) yuuji@53: (YaTeX-reindent depth)))) yuuji@53: yuuji@53: ;;;###autoload yuuji@53: (defun YaTeX-goto-corresponding-leftright () yuuji@77: "Go to corresponding \left or \right." yuuji@53: (let ((YaTeX-struct-begin "\\left%1") yuuji@53: (YaTeX-struct-end "\\right%1") yuuji@77: (YaTeX-struct-name-regexp "[][(){}\\.|]") yuuji@77: (in-leftright-p t)) yuuji@53: (YaTeX-goto-corresponding-environment t))) yuuji@53: yuuji@53: ;;; yuuji@53: ;; Functions for formatting region being enclosed with environment yuuji@53: ;;; yuuji@53: ; These functions must take two argument; region-beginning, region-end. yuuji@53: yuuji@53: (defun YaTeX-enclose-equation (beg end) yuuji@53: (goto-char beg) yuuji@53: (save-restriction yuuji@53: (let (m0 bsl) yuuji@53: (narrow-to-region beg end) yuuji@53: (while (YaTeX-re-search-active-forward yuuji@53: "\\(\\$\\)" YaTeX-comment-prefix nil t) yuuji@53: (goto-char (setq m0 (match-beginning 0))) yuuji@53: (setq bsl 0) yuuji@53: (if (and (not (bobp)) (= (char-after (1- (point))) ?\\ )) yuuji@53: (while (progn (forward-char -1) (= (char-after (point)) ?\\ )) yuuji@53: (setq bsl (1+ bsl)))) yuuji@53: (goto-char m0) yuuji@53: (if (= 0 (% bsl 2)) yuuji@53: (delete-char 1) yuuji@53: (forward-char 1)))))) yuuji@53: yuuji@53: (fset 'YaTeX-enclose-eqnarray 'YaTeX-enclose-equation) yuuji@53: (fset 'YaTeX-enclose-eqnarray* 'YaTeX-enclose-equation) yuuji@457: (mapcar (function ;; Add all AMS LaTeX envs yuuji@457: (lambda (sym) yuuji@457: (fset (intern (concat "YaTeX-enclose-" (car sym))) yuuji@457: 'YaTeX-enclose-equation))) yuuji@457: YaTeX-ams-math-begin-alist) yuuji@53: yuuji@53: (defun YaTeX-enclose-verbatim (beg end)) ;do nothing when enclose verbatim yuuji@53: (fset 'YaTeX-enclose-verbatim* 'YaTeX-enclose-verbatim) yuuji@53: yuuji@53: (provide 'yatexenv)