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