(concat "([ \t\n]*\\_<" (regexp-opt '("dolist" "dotimes")))
"Regular expression matching sexps containing one variable binding.")
-(defun company-elisp-parse-local (prefix vars)
+(defun company-elisp-locals (prefix)
(let ((regexp (concat "[ \t\n]*\\(\\_<" (regexp-quote prefix)
"\\(?:\\sw\\|\\s_\\)*\\_>\\)"))
- (pos (point)))
+ (pos (point))
+ res)
(ignore-errors
(save-excursion
(dotimes (i company-elisp-parse-depth)
(and (looking-at regexp)
;; Don't add incomplete text as candidate.
(not (eq (match-end 0) pos))
- (add-to-list 'vars (match-string-no-properties 1))))
+ (push (match-string-no-properties 1) res)))
(forward-sexp))))
((looking-at company-elisp-binding-regexp-1)
(down-list 2)
(and (looking-at regexp)
;; Don't add incomplete text as candidate.
(not (eq (match-end 0) pos))
- (add-to-list 'vars (match-string-no-properties 1)))))))))
- vars))
+ (pushnew (match-string-no-properties 1) res))))))))
+ res))
(defun company-elisp-candidates (prefix)
+ (append (company-elisp-locals prefix)
+ (company-elisp-globals prefix
+ (company-elisp-candidates-predicate prefix))))
+
+(defun company-elisp-globals (prefix predicate)
+ (all-completions prefix obarray predicate))
+
+(defun company-elisp-candidates-predicate (prefix)
(let* ((completion-ignore-case nil)
- (before (char-before (- (point) (length prefix))))
- (predicate (if (and company-elisp-detect-function-context
- (not (eq before ?')))
- (if (eq before ?\()
- 'fboundp
- 'boundp)
- 'company-elisp-predicate))
- (candidates (all-completions prefix obarray predicate)))
- (company-elisp-parse-local prefix candidates)))
+ (before (char-before (- (point) (length prefix)))))
+ (if (and company-elisp-detect-function-context
+ (not (eq before ?')))
+ (if (and (eq before ?\()
+ (not
+ (save-excursion
+ (ignore-errors
+ (up-list -2)
+ (forward-char 1)
+ (looking-at " *(")))))
+ 'fboundp
+ 'boundp)
+ 'company-elisp-predicate)))
(defun company-elisp-doc (symbol)
(let* ((symbol (intern symbol))
(apply command args)
(let ((this-command command))
(run-hooks 'post-command-hook))))
+
+(defmacro company-elisp-with-buffer (contents &rest body)
+ (declare (indent 0))
+ `(with-temp-buffer
+ (insert ,contents)
+ (re-search-backward "|")
+ (replace-match "")
+ ,@body))
+
+(ert-deftest company-elisp-candidates-predicate ()
+ (company-elisp-with-buffer
+ "(foo ba|)"
+ (should (eq (let ((company-elisp-detect-function-context t))
+ (company-elisp-candidates-predicate "ba"))
+ 'boundp))
+ (should (eq (let (company-elisp-detect-function-context)
+ (company-elisp-candidates-predicate "ba"))
+ 'company-elisp-predicate)))
+ (company-elisp-with-buffer
+ "(foo| )"
+ (should (eq (let ((company-elisp-detect-function-context t))
+ (company-elisp-candidates-predicate "foo"))
+ 'fboundp))
+ (should (eq (let (company-elisp-detect-function-context)
+ (company-elisp-candidates-predicate "foo"))
+ 'company-elisp-predicate)))
+ (company-elisp-with-buffer
+ "(foo 'b|)"
+ (should (eq (let ((company-elisp-detect-function-context t))
+ (company-elisp-candidates-predicate "b"))
+ 'company-elisp-predicate))))
+
+;; Mix it up with an integration test.
+(ert-deftest company-elisp-candidates-recognizes-binding-form ()
+ (company-elisp-with-buffer
+ "(let ((foo 7) (wh| )))"
+ (let ((obarray [when what whelp])
+ (what 1)
+ (whelp 2)
+ (wisp 3))
+ (should (equal '("what" "whelp")
+ (let ((company-elisp-detect-function-context t))
+ (company-elisp-candidates "wh")))))))
+
+(ert-deftest company-elisp-finds-vars ()
+ (let ((obarray [boo bar baz backquote])
+ (boo t)
+ (bar t)
+ (baz t))
+ (should (equal '("bar" "baz")
+ (company-elisp-globals "ba" 'boundp)))))
+
+(ert-deftest company-elisp-finds-functions ()
+ (let ((obarray [when what whelp])
+ (what t)
+ (whelp t))
+ (should (equal '("when")
+ (company-elisp-globals "wh" 'fboundp)))))
+
+(ert-deftest company-elisp-finds-things ()
+ (let ((obarray [when what whelp])
+ (what t)
+ (whelp t))
+ (should (equal '("what" "whelp" "when")
+ (sort (company-elisp-globals "wh" 'company-elisp-predicate)
+ 'string<)))))