[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
feature/capf 83eddfa3: latex-capf.el: Make it work
From: |
Arash Esbati |
Subject: |
feature/capf 83eddfa3: latex-capf.el: Make it work |
Date: |
Fri, 14 Oct 2022 06:32:24 -0400 (EDT) |
branch: feature/capf
commit 83eddfa38ef073d78b6808cf4e79f50fa970ffaf
Author: Arash Esbati <arash@gnu.org>
Commit: Arash Esbati <arash@gnu.org>
latex-capf.el: Make it work
---
latex-capf.el | 313 +++++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 221 insertions(+), 92 deletions(-)
diff --git a/latex-capf.el b/latex-capf.el
index 9c8af3b8..aca92127 100644
--- a/latex-capf.el
+++ b/latex-capf.el
@@ -22,58 +22,81 @@ several lines in TeX."
"Find out if point is within the arguments of any TeX-macro.
The return value is
- (\"name\" mac-or-env integer type)
+ (\"name\" mac-or-env total-num type opt-num opt-distance)
\"name\" is the name of the macro (without backslash) or
environment as a string.
mac-or-env is one of the symbols `mac' or `env'.
-integer is the number of the argument where we started.
+total-num is the total number of the argument before the point started.
type is one of the symbols `mandatory' or `optional'.
+opt-num is the number of optional arguments before the point started.
+opt-distance the number of optional arguments after the last mandatory.
-If the optional BOUND is an integer, bound backwards directed
-searches to this point. If it is nil, limit to the previous 15
-lines."
- ;; Exit if we're not inside a list or inside a nested list:
- (unless (/= (car (syntax-ppss)) 1)
- (let ((bound (or bound (line-beginning-position -15)))
- (env-or-mac 'mac)
- cmd cnt cnt-opt type)
+If the optional BOUND is an integer, limit backward searches to
+this point. If nil, limit to the previous 15 lines."
+ (let ((bound (or bound (line-beginning-position -15)))
+ (env-or-mac 'mac)
+ cmd cnt cnt-opt type result ;; env-or-mac-start
+ (cnt-distance 0))
+ (save-excursion
+ (save-restriction
+ (narrow-to-region (max (point-min) bound) (point-max))
+ ;; Move back out of the current parenthesis
+ (let ((forward-sexp-function nil))
+ (up-list -1))
+ ;; Set the initial value of argument counter
+ (setq cnt 1)
+ ;; Note that we count also the right opt. or man. arg:
+ (setq cnt-opt (if (= (following-char) ?\{) 0 1))
+ ;; Record if we're inside a mand. or opt. argument
+ (setq type (if (= (following-char) ?\{) 'mandatory 'optional))
+ ;; Move back over any touching sexps
+ (while (and (TeX-move-to-previous-arg bound)
+ (condition-case nil
+ (let ((forward-sexp-function nil))
+ (backward-sexp) t)
+ (error nil)))
+ (when (eq (following-char) ?\[)
+ (cl-incf cnt-opt))
+ (cl-incf cnt))
+ ;; (setq env-or-mac-start (point))
+ (when (and (or (= (following-char) ?\[)
+ (= (following-char) ?\{))
+ (re-search-backward "\\\\[*a-zA-Z]+\\=" nil t))
+ (setq cmd (TeX-match-buffer 0))
+ (when (looking-at "\\\\begin{\\([^}]+\\)}")
+ (setq cmd (TeX-match-buffer 1))
+ (setq env-or-mac 'env)
+ (cl-decf cnt))
+ (when (and cmd (not (string= cmd "")))
+ (setq result (list (if (eq env-or-mac 'mac)
+ ;; Strip leading backslash from
+ ;; the macro
+ (substring cmd 1)
+ cmd)
+ env-or-mac cnt type cnt-opt))))))
+ ;; If we were inside an optional argument after a mandatory one,
+ ;; we have to find out the number of optional arguments before
+ ;; the mandatory one.
+ (when (and (eq (nth 3 result) 'optional)
+ (/= 0 (- (nth 2 result) (nth 4 result))))
(save-excursion
(save-restriction
(narrow-to-region (max (point-min) bound) (point-max))
- ;; Move back out of the current parenthesis
(let ((forward-sexp-function nil))
(up-list -1))
- ;; Set the initial value of argument counter
- (setq cnt 1)
- ;; Note that we count also the right opt. or man. arg:
- (setq cnt-opt (if (= (following-char) ?\{) 0 1))
- ;; Record if we're inside a mand. or opt. argument
- (setq type (if (= (following-char) ?\{) 'mandatory 'optional))
- ;; Move back over any touching sexps
+ (unless (= (following-char) ?\{)
+ (cl-incf cnt-distance))
(while (and (TeX-move-to-previous-arg bound)
(condition-case nil
(let ((forward-sexp-function nil))
- (backward-sexp) t)
+ (backward-sexp)
+ (/= (following-char) ?\{))
(error nil)))
- (if (eq (following-char) ?\[) (cl-incf cnt-opt))
- (cl-incf cnt))
- (when (and (or (= (following-char) ?\[)
- (= (following-char) ?\{))
- (re-search-backward "\\\\[*a-zA-Z]+\\=" nil t))
- (setq cmd (TeX-match-buffer 0))
- (when (looking-at "\\\\begin{\\([^}]+\\)}")
- (setq cmd (TeX-match-buffer 1))
- (setq env-or-mac 'env)
- (cl-decf cnt))
- (if (and cmd (not (string= cmd "")))
- (list (if (eq env-or-mac 'mac)
- ;; Strip leading backslash from
- ;; the macro
- (substring cmd 1)
- cmd)
- env-or-mac cnt type)
- nil)))))))
+ (cl-incf cnt-distance)))))
+ ;; Check if we really have a result before adding something new:
+ (when result
+ (append result (list cnt-distance)))))
(defun LaTeX-completion-candidates-key-val (key-vals)
;; First find out if we're looking for a key or a value: If we're
@@ -130,74 +153,180 @@ lines."
(lambda (_)
(funcall func key-vals))))))))
+(defun LaTeX-completion-candidates-completing-read-multiple (collection)
+ (let ((end (point))
+ beg list-beg)
+ (save-excursion
+ (up-list -1)
+ (setq list-beg (1+ (point))))
+ (save-excursion
+ (unless (search-backward "," list-beg t)
+ (goto-char list-beg))
+ (skip-chars-forward "^a-zA-Z0-9" end)
+ (setq beg (point)))
+ (list beg end (completion-table-dynamic
+ (lambda (_)
+ collection)))))
+
(defun LaTeX-completion-candidates-completing-read (collection)
(let ((end (point))
- beg key) ))
+ beg)
+ (save-excursion
+ (up-list -1)
+ (forward-char)
+ (skip-chars-forward "^a-zA-Z0-9" end)
+ (setq beg (point)))
+ (list beg end (completion-table-dynamic
+ (lambda (_)
+ collection)))))
-(defun LaTeX-completion-candidates-completing-read-multiple (table)
- nil)
+(defun LaTeX-completion-parse-args (entry)
+ (let* ((name (nth 0 entry))
+ (mac-or-env (nth 1 entry))
+ (total-num (nth 2 entry))
+ (type (nth 3 entry))
+ (opt-num (nth 4 entry))
+ (opt-dis (nth 5 entry))
+ (mand-num (- total-num opt-num))
+ (cnt 0)
+ (again t)
+ arg-list result)
+ (setq arg-list (cdr (assoc name (if (eq mac-or-env 'mac)
+ (TeX-symbol-list)
+ (LaTeX-environment-list)))))
+ ;; FIXME: Check for `TeX-arg-conditional' here and change
+ ;; `arg-list' accordingly
+ ;;
+ ;; Check if there is a `LaTeX-env-args' in the `arg-list' and
+ ;; remove it:
+ (when (and (eq mac-or-env 'env)
+ (eq (car arg-list) #'LaTeX-env-args))
+ (pop arg-list))
+ (cond ((and (eq type 'optional)
+ (= opt-dis 0))
+ ;; Optional arg without mandatory one before: This case is
+ ;; straight and we just pick the correct one out of the
+ ;; list:
+ (setq result (nth (1- total-num) arg-list)))
+ ;; Mandatory arg: Loop over the arg-list and drop all
+ ;; vectors at the list beginning:
+ ((eq type 'mandatory)
+ (while (vectorp (car arg-list))
+ (pop arg-list))
+ ;; The next entry must be a mandatory arg. If we're
+ ;; looking for the first mandatory argument, just pick the
+ ;; first element. Otherwise loop further over the list and
+ ;; count for the correct arg:
+ (if (= mand-num 1)
+ (setq result (car arg-list))
+ (while again
+ (cond ((vectorp (car arg-list))
+ (pop arg-list)
+ (setq again t))
+ ((= (cl-incf cnt) mand-num)
+ (setq again nil)
+ (setq result (car arg-list)))
+ (t
+ ;; Be a little conservative against infloops.
+ (if arg-list
+ (progn (setq again t)
+ (pop arg-list))
+ (setq again nil)))))))
+ ;; Optional arg after mandatory one(s): This isn't fun :-(
+ ((and (eq type 'optional)
+ (/= opt-dis 0))
+ (setq again t)
+ (setq cnt 0)
+ ;; The idea is: Look for non-vectors and count the number
+ ;; of mandatory argument in `mand-num'.
+ (while again
+ (cond ((and (not (vectorp (car arg-list)))
+ (/= (cl-incf cnt) mand-num))
+ (pop arg-list)
+ (setq again t))
+ ((and (not (vectorp (car arg-list)))
+ ;; Don't incf mand-num again; is done in the
+ ;; clause above:
+ (= cnt mand-num))
+ (setq again nil))
+ ;; If the clauses above fail, we can safely drop
+ ;; vectors:
+ ((vectorp (car arg-list))
+ (pop arg-list)
+ (setq again t))
+ (t
+ (setq again nil))))
+ (setq result (nth opt-dis arg-list)))
+ (t nil))
+ result))
(defun LaTeX-completion-parse-arg (arg)
"Prepare ARG suitable for further completion processing."
- (when (and (or (vectorp arg)
- (listp arg))
- (symbolp (elt arg 0))
- (fboundp (elt arg 0)))
+ (when (or (and (vectorp arg)
+ (fboundp (elt arg 0)))
+ (and (listp arg)
+ (fboundp (car arg)))
+ (and (symbolp arg)
+ (fboundp arg)))
;; Turn a vector into a list:
(when (vectorp arg)
(setq arg (append arg nil)))
- (let ((head (car arg))
- (tail (cadr arg)))
+ ;; Turn a single function symbol into a list:
+ (unless (listp arg)
+ (setq arg (list arg)))
+ (let* ((head (car arg))
+ (tail (cadr arg))
+ (fun1 (lambda (elt)
+ (cond ((symbolp elt)
+ ;; It is a variable name
+ (symbol-value elt))
+ ;; It is a function call ...
+ ((and (listp elt)
+ (symbolp (car elt))
+ (fboundp (car elt)))
+ ;; ... w/ or w/o args:
+ (if (= (length elt) 1)
+ (funcall (car elt))
+ (eval elt t)))
+ ;; It is a plain list of strings:
+ (t elt)))))
(cond ((eq head #'TeX-arg-key-val)
(LaTeX-completion-candidates-key-val
- (cond ((symbolp tail)
- ;; It is a variable name
- (symbol-value tail))
- ;; It is a function call ...
- ((and (listp tail)
- (symbolp (car tail))
- (fboundp (car tail)))
- ;; ... w/ or w/o args:
- (if (= (length tail) 1)
- (funcall (car tail))
- (eval tail t)))
- ;; It is a plain list of strings:
- (t tail))))
- ) )))
+ (funcall fun1 tail)))
+ ((eq head #'TeX-arg-completing-read-multiple)
+ (LaTeX-completion-candidates-completing-read-multiple
+ (funcall fun1 tail)))
+ ((eq head #'TeX-arg-completing-read)
+ (LaTeX-completion-candidates-completing-read
+ (funcall fun1 tail)))
+ ((assq (car arg) LaTeX-completion-function-map-alist)
+ (funcall (cdr (assq (car arg)
LaTeX-completion-function-map-alist))))
+ (t nil)))))
+
+(defvar LaTeX-completion-function-map-alist
+ '((TeX-arg-counter . LaTeX-counter-list)
+ (TeX-arg-pagestyle . LaTeX-pagestyle-list)
+ ;; ...
+ )
+ "Alist mapping inserting funcs to their completion-candidates counterparts.
+Each element is a cons with the name of the function which
+queries and inserts something in the buffer as car and the name
+function delievering completion candidates as cdr.")
(defun LaTeX-arguments-completion-at-point ()
;; Exit if not inside a list or a nested list or in a comment:
- (unless (or (/= (car (syntax-ppss)) 1)
- (TeX-in-comment))
- (let ((entry (LaTeX-what-macro))
- mac env arg)
- (cond ((eq (nth 1 entry) 'mac)
- ;; Feed 'arg' to `LaTeX-completion-parse-arg' only when
- ;; we find one:
- (and (setq mac (assoc (car entry) (TeX-symbol-list)))
- (setq arg (nth (nth 2 entry) mac))
- (LaTeX-completion-parse-arg arg)))
- ((eq (nth 1 entry) 'env)
- ;; Feed 'arg' to `LaTeX-completion-parse-arg' only when
- ;; we find one:
- (and (setq env (assoc (car entry) (LaTeX-environment-list)))
- ;; Shift the number of arg if `LaTeX-env-args' is present:
- (setq arg (if (eq (cadr env) 'LaTeX-env-args)
- (nth (1+ (nth 2 entry)) env)
- (nth (nth 2 entry) env)))
- (LaTeX-completion-parse-arg arg)))
+ (when (or (/= (car (syntax-ppss)) 0)
+ (not (TeX-in-comment)))
+ (let ((entry (LaTeX-what-macro)))
+ (cond ((or (and (eq (nth 1 entry) 'mac)
+ (assoc (car entry) (TeX-symbol-list)))
+ (and (eq (nth 1 entry) 'env)
+ (assoc (car entry) (LaTeX-environment-list))))
+ ;; Check if we find the macro name inside
+ ;; `TeX-symbol-list' or the env name inside
+ ;; `LaTeX-environment-list' otherwise don't start the
+ ;; procedure:
+ (LaTeX-completion-parse-arg
+ (LaTeX-completion-parse-args entry)))
;; Any other constructs?
(t nil)))))
-
-;; (defun LaTeX-completion-candidates-single (func)
-
-;; (let ((end (point))
-;; beg)
-;; (cond ((eq func #'TeX-arg-pagestyle)
-;; (save-excursion
-;; (skip-chars-backward "a-zA-Z0-9")
-;; (setq beg (point)))
-;; (list beg end (completion-table-dynamic
-;; (lambda (_) (LaTeX-pagestyle-list)))))
-;; (t nil))
-;; ))
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- feature/capf 83eddfa3: latex-capf.el: Make it work,
Arash Esbati <=