changeset 106134:cff2b8b6d64e

(latex-complete-bibtex-cache, latex-complete-alist): New vars. (latex-string-prefix-p, latex-complete-bibtex-keys, latex-complete-data) (latex-complete-envnames, latex-complete-refkeys): New functions. (latex-complete, latex-indent-or-complete): New commands.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Thu, 19 Nov 2009 22:55:41 +0000
parents 5e6998ac1a2e
children 44eb0cd5515b
files lisp/ChangeLog lisp/textmodes/tex-mode.el
diffstat 2 files changed, 117 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/ChangeLog	Thu Nov 19 22:10:40 2009 +0000
+++ b/lisp/ChangeLog	Thu Nov 19 22:55:41 2009 +0000
@@ -1,5 +1,12 @@
 2009-11-19  Stefan Monnier  <monnier@iro.umontreal.ca>
 
+	* textmodes/tex-mode.el (latex-complete-bibtex-cache)
+	(latex-complete-alist): New vars.
+	(latex-string-prefix-p, latex-complete-bibtex-keys)
+	(latex-complete-envnames, latex-complete-refkeys)
+	(latex-complete-data): New functions.
+	(latex-complete, latex-indent-or-complete): New commands.
+
 	* window.el (display-buffer-mark-dedicated): New var.
 	(display-buffer): Obey it.
 	* minibuffer.el (minibuffer-completion-help): Use it.
--- a/lisp/textmodes/tex-mode.el	Thu Nov 19 22:10:40 2009 +0000
+++ b/lisp/textmodes/tex-mode.el	Thu Nov 19 22:55:41 2009 +0000
@@ -1420,6 +1420,116 @@
   \n "\\item " >)
 
 
+;;;; LaTeX completion.
+
+(defvar latex-complete-bibtex-cache nil)
+
+(defun latex-string-prefix-p (str1 str2)
+  (eq t (compare-strings str1 nil nil str2 0 (length str1))))
+
+(defvar bibtex-reference-key)
+(declare-function reftex-get-bibfile-list "reftex-cite.el" ())
+
+(defun latex-complete-bibtex-keys ()
+  (when (bound-and-true-p reftex-mode)
+    (lambda (key pred action)
+      (let ((re (concat "^[ \t]*@\\([a-zA-Z]+\\)[ \t\n]*\\([{(][ \t\n]*\\)"
+                        (regexp-quote key)))
+            (files (reftex-get-bibfile-list))
+            keys)
+        (if (and (eq (car latex-complete-bibtex-cache)
+                     (reftex-get-bibfile-list))
+                 (latex-string-prefix-p (nth 1 latex-complete-bibtex-cache)
+                                        key))
+            ;; Use the cache.
+            (setq keys (nth 2 latex-complete-bibtex-cache))
+          (dolist (file files)
+            (with-current-buffer (find-file-noselect file)
+              (goto-char (point-min))
+              (while (re-search-forward re nil t)
+                (goto-char (match-end 2))
+                (when (and (not (member-ignore-case (match-string 1)
+                                                    '("c" "comment" "string")))
+                           (looking-at bibtex-reference-key))
+                  (push (match-string-no-properties 0) keys)))))
+          ;; Fill the cache.
+          (set (make-local-variable 'latex-complete-bibtex-cache)
+               (list files key keys)))
+        (complete-with-action action keys key pred)))))
+
+(defun latex-complete-envnames ()
+  (append latex-block-names latex-standard-block-names))
+
+(defun latex-complete-refkeys ()
+  (when (boundp 'reftex-docstruct-symbol)
+    (symbol-value reftex-docstruct-symbol)))
+
+(defvar latex-complete-alist
+  ;; TODO: Add \begin, \end, \ref, ...
+  '(("\\`\\\\\\(short\\)?cite\\'" . latex-complete-bibtex-keys)
+    ("\\`\\\\\\(begin\\|end\\)\\'" . latex-complete-envnames)
+    ("\\`\\\\[vf]?ref\\'" . latex-complete-refkeys)))
+
+(defun latex-complete-data ()
+  "Get completion-data at point."
+  (save-excursion
+    (let ((pt (point)))
+      (skip-chars-backward "^ {}\n\t\\\\")
+      (case (char-before)
+        ((nil ?\s ?\n ?\t ?\}) nil)
+        (?\\
+         ;; TODO: Complete commands.
+         nil)
+        (?\{
+         ;; Complete args to commands.
+         (let* ((cmd
+                 (save-excursion
+                   (forward-char -1)
+                   (skip-chars-backward " \n")
+                   (buffer-substring (point)
+                                     (progn
+                                       (skip-chars-backward "a-zA-Z@*")
+                                       (let ((n (skip-chars-backward "\\\\")))
+                                         (forward-char (* 2 (/ n 2))))
+                                       (point)))))
+                (start (point))
+                (_ (progn (goto-char pt) (skip-chars-backward "^," start)))
+                (comp-beg (point))
+                (_ (progn (goto-char pt) (skip-chars-forward "^, {}\n\t\\\\")))
+                (comp-end (point))
+                (table
+                 (funcall
+                  (let ((f (lambda () t)))
+                    (dolist (comp latex-complete-alist)
+                      (if (string-match (car comp) cmd)
+                          (setq f (cdr comp))))
+                    f))))
+           (if (eq table t)
+               ;; Unknown command.
+               nil
+             (list comp-beg comp-end table))))))))
+
+(defun latex-complete ()
+  "Perform completion at point for LaTeX mode.
+Return non-nil if we found what to complete."
+  (interactive)
+  (let ((data (latex-complete-data)))
+    (when data
+      (apply 'completion-in-region data)
+      t)))
+
+(defun latex-indent-or-complete ()
+  "Perform completion at point or indentation, according to DWIM.
+The heuristic is to try indentation, if that fails try completion,
+if that fails insert a tab."
+  (interactive)
+  (let ((undo buffer-undo-list)
+	(pos (point)))
+    (indent-according-to-mode)
+    (or (not (and (eq pos (point)) (eq undo buffer-undo-list)))
+        (latex-complete)
+        (insert-tab))))
+
 ;;;;
 ;;;; LaTeX syntax navigation
 ;;;;